Aller au contenu
Cloud medium

feint : émuler Scaleway, Outscale et Exoscale en local

30 min de lecture

Logo feint

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.

  • 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é.
  • 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.
  • 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.

  • Une machine Linux ou macOS en x86-64 ou ARM64.
  • cosign et jq pour la vérification d'installation, gh en 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.2.0 publie les binaires, un fichier checksums.txt, sa signature Sigstore et une attestation de provenance SLSA.

  1. Récupérer les artefacts de la version.

    Fenêtre de terminal
    base=https://github.com/stephrobert/feint/releases/download/v0.2.0
    curl -fsSLO "$base/feint-linux-amd64"
    curl -fsSLO "$base/checksums.txt"
    curl -fsSLO "$base/checksums.txt.cosign.bundle"
  2. 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/.*' \
    --certificate-oidc-issuer https://token.actions.githubusercontent.com \
    checksums.txt

    La sortie attendue tient en deux mots : Verified OK. Toute autre réponse doit arrêter l'installation.

  3. Vérifier les octets contre la liste signée.

    Fenêtre de terminal
    sha256sum -c checksums.txt --ignore-missing

    Le 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.

  4. Installer le binaire et confirmer la version.

    Fenêtre de terminal
    install -m 0755 feint-linux-amd64 ~/.local/bin/feint
    feint version

    La sortie doit afficher v0.2.0.

Si vous préférez la provenance à la signature, gh vérifie quel workflow et quel commit ont produit le binaire :

Fenêtre de terminal
gh attestation verify feint-linux-amd64 --repo stephrobert/feint

Depuis la version 0.2.0, 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.

Fenêtre de terminal
feint version --check

Trois 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.2.0
base=https://github.com/stephrobert/feint/releases/download/v0.2.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.2.0

La 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.2.0
this is the latest release

Le troisième cas concerne les binaires construits localement :

the latest release is v0.2.0 (this build reports "dev", which is not a released version)
https://github.com/stephrobert/feint/releases/tag/v0.2.0

Un 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é.

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.

Fenêtre de terminal
feint doctor

Sortie de feint doctor : port libre, runtime Incus détecté, clients officiels trouvés, avertissements sur les contrats et sur ProxyJump

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.

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.

Fenêtre de terminal
feint start
feint listening on 127.0.0.1:4599 (pid 1155265)
logs: /run/user/1000/feint/127.0.0.1_4599/feint.log

L'é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 :

Fenêtre de terminal
feint status
running on 127.0.0.1:4599 (pid 1155265, since 2026-07-30T09:39:36Z)
resources 21
machines none
provider routes driven by a client
scaleway 55 0
outscale 20 0
exoscale 14 0

La 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é. 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.

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.

Fenêtre de terminal
eval "$(feint env scaleway)"
scw instance server create name=web-01 type=DEV1-S image=ubuntu_jammy zone=fr-par-1
scw instance server list zone=fr-par-1

Le CLI Scaleway officiel pilote l'émulateur : création puis liste d'un serveur DEV1-S

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 :

Fenêtre de terminal
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"}

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.

Fenêtre de terminal
eval "$(feint env outscale)"
oapi-cli CreateNet --IpRange 10.0.0.0/16
oapi-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 provider Scaleway se détourne avec un seul réglage, api_url. Le reste de la configuration reste celle que vous écririez pour le vrai fournisseur, ce qui est tout l'intérêt : vous testez le code que vous déploierez.

terraform {
required_providers {
scaleway = {
source = "scaleway/scaleway"
version = "~> 2.79"
}
}
}
provider "scaleway" {
access_key = "SCWXXXXXXXXXXXXXXXXX"
secret_key = "11111111-1111-1111-1111-111111111111"
project_id = "11111111-1111-1111-1111-111111111111"
organization_id = "99999999-9999-4999-8999-999999999999"
region = "fr-par"
zone = "fr-par-1"
api_url = "http://127.0.0.1:4599"
}
resource "scaleway_vpc" "lab" {
name = "lab-feint"
}
resource "scaleway_vpc_private_network" "lab" {
name = "reseau-interne"
vpc_id = scaleway_vpc.lab.id
}
resource "scaleway_instance_server" "web" {
name = "web-terraform"
type = "DEV1-S"
image = "ubuntu_jammy"
}

L'application se déroule sans adaptation particulière :

Fenêtre de terminal
terraform init
terraform apply -auto-approve
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
private_network_id = "fr-par/a0fa6f82-2aad-4f82-985a-2abeb65f05f7"
server_id = "fr-par-1/d2303f04-8ab3-4e71-a682-ad91c81286b7"

Les identifiants renvoyés portent le préfixe de région ou de zone, comme chez Scaleway. Un terraform destroy fonctionne symétriquement, ce qui permet de valider un cycle complet dans une CI sans créer la moindre ressource facturée. Pour la construction des configurations elles-mêmes, la section Terraform du site couvre le sujet en profondeur.

Comment obtenir de vraies machines derrière l'API

Section intitulée « Comment obtenir de vraies machines derrière l'API »

Par défaut, feint est un plan de contrôle : il répond, et rien ne tourne. Donnez-lui un runtime et un serveur créé devient un conteneur ou une machine virtuelle réelle, sur un vrai pont réseau, portant l'adresse que l'API a publiée. C'est la différence entre un émulateur et un simple serveur de maquettes.

Les quatre modes ne délivrent pas la même chose, et un seul écart compte vraiment :

--vmMachinesAdressesPare-feuIsolation inter-VPCNoyau propreNécessite
off (défaut)nonnonnonnonnonrien
incusouiouiouinonnonIncus 6.0.4+
incus-vmouiouiouinonouiIncus + KVM
incus-ovnouiouiouiouinonIncus + OVN

L'isolation est la seule capacité qui change de verdict selon le mode. Deux réseaux privés de deux VPC différents ne doivent pas se joindre. En mode pont, ils se joignent, et la cause est documentée par le runtime lui-même : le trafic entre ponts gérés sur un même hôte est routé directement. Un réseau OVN est un réseau logique doté de son propre routeur, donc la séparation vient de la topologie et non d'une règle.

Plutôt que de deviner, demandez à l'émulateur ce que son mode sait prouver :

Fenêtre de terminal
feint start --vm incus
curl -s localhost:4599/_feint/health | jq -c '.capabilities'
{"machines":true,"addresses":true,"firewall":true,"isolation":false,"own_kernel":false}

Le même appel en --vm incus-ovn renvoie "isolation":true. Cette déclaration est faite pour être lue par vos tests : une suite qui compare un nom de mode en dur doit être modifiée à chaque évolution, une suite qui lit les capacités continue de fonctionner.

Debian 13 est la distribution la plus simple pour ce mode, et la procédure tient en trois temps : le dépôt, les paquets, le câblage OVN. C'est ce dernier que personne ne devine, et sans lui incus network create --type=ovn échoue avec une erreur qui ne nomme ni la cause ni le réglage manquant.

Un mot sur le choix du dépôt, parce qu'il se discute. Debian 13 « trixie » package Incus 6.0.4, exactement le plancher en dessous duquel les listes de contrôle d'accès sur une interface sont refusées. Le paquet de la distribution suffit donc, contrairement à Ubuntu 24.04 qui livre 6.0.0 et ne bougera plus. Le dépôt Zabbly, publié par le mainteneur d'Incus, apporte la série 7.2 recommandée, celle sur laquelle les mesures du projet ont été faites. Sur ma VM Debian 13, apt-cache policy incus affiche bien 6.0.4-2+deb13u8 avant l'ajout du dépôt.

  1. Installer les prérequis et récupérer la clé du dépôt dans son propre trousseau. Une clé déposée dans /etc/apt/keyrings ne signe que le dépôt qui la nomme, là où le magasin système vaudrait pour tout.

    Fenêtre de terminal
    apt-get update
    apt-get install -y --no-install-recommends ca-certificates curl gpg uidmap
    mkdir -p /etc/apt/keyrings
    curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
    gpg --show-keys --with-fingerprint /etc/apt/keyrings/zabbly.asc

    Vérifiez l'empreinte affichée avant de continuer : elle doit valoir 4EFC 5906 96CB 15B8 7C73 A3AD 82CC 8797 C838 DCFD, pour Zabbly Kernel Builds. C'est le seul moment où vous décidez à qui vous faites confiance.

  2. Déclarer le dépôt, en dérivant la suite et l'architecture de la machine plutôt qu'en les écrivant en dur.

    Fenêtre de terminal
    cat > /etc/apt/sources.list.d/zabbly-incus.sources <<EOF
    Enabled: yes
    Types: deb
    URIs: https://pkgs.zabbly.com/incus/stable
    Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
    Components: main
    Architectures: $(dpkg --print-architecture)
    Signed-By: /etc/apt/keyrings/zabbly.asc
    EOF

    Sur Debian 13, Suites vaut trixie. Aucun curl | sh dans cette procédure : chaque fichier est écrit sur disque, et la clé est vérifiée avant que le moindre paquet n'arrive.

  3. Installer Incus, OVN et Open vSwitch. Incus vient de Zabbly, les paquets OVN de Debian.

    Fenêtre de terminal
    apt-get update
    apt-get install -y --no-install-recommends \
    incus incus-client ovn-central ovn-host openvswitch-switch

    Contrôle immédiat : incus --version doit répondre 7.2 et ovn-nbctl --version ovn-nbctl 25.03.0 sur une trixie à jour.

  4. Démarrer les services, puis attendre. Les unités systemd rendent la main avant que les bases de données OVN n'écoutent, et une commande lancée dans cet intervalle échoue sans raison apparente.

    Fenêtre de terminal
    systemctl enable --now openvswitch-switch ovn-central ovn-host
    while [ ! -S /run/ovn/ovnnb_db.sock ]; do sleep 1; done
  5. Indiquer à Open vSwitch où se trouve la base southbound. C'est la moitié du câblage, celle qui relie le commutateur au plan de contrôle OVN.

    Fenêtre de terminal
    ovs-vsctl set open_vswitch . \
    external_ids:ovn-remote=unix:/run/ovn/ovnsb_db.sock \
    external_ids:ovn-encap-type=geneve \
    external_ids:ovn-encap-ip=127.0.0.1
  6. Initialiser Incus, puis donner au pont d'uplink la plage que les réseaux OVN viendront y découper.

    Fenêtre de terminal
    incus admin init --minimal
    incus network set incusbr0 ipv4.address=10.108.0.1/24
    incus network set incusbr0 \
    ipv4.dhcp.ranges=10.108.0.10-10.108.0.99 \
    ipv4.ovn.ranges=10.108.0.100-10.108.0.199

    L'adresse se fixe dans une commande séparée des plages : celles-ci sont validées contre l'adresse courante du pont, et incus admin init --minimal en choisit une au hasard. Sans ipv4.ovn.ranges, la création d'un réseau OVN est refusée avec un message qui accuse le réseau plutôt que le pont.

  7. Vérifier par un vrai réseau, pas par la liste des paquets installés.

    Fenêtre de terminal
    incus network create ovntest --type=ovn network=incusbr0
    incus network delete ovntest

    Network ovntest created valide l'ensemble du câblage. C'est le seul contrôle qui prouve quelque chose : des paquets installés mais mal reliés passent tous les autres.

Ne désactivez pas AppArmor. La tentation existe, parce que l'intégration continue du projet OVN coupe AppArmor avant ses tests système. Ce contournement vise des binaires compilés depuis les sources, hors des chemins couverts par les profils packagés. Une installation par paquets embarque les profils dont elle a besoin : sur la VM de test, Incus, OVN et Open vSwitch fonctionnent tous avec AppArmor actif. Couper un contrôle d'accès obligatoire pour faire tourner un outil de test est un mauvais échange.

Le verdict final ne se lit pas dans apt, mais dans la capacité déclarée :

Fenêtre de terminal
feint doctor --vm auto
feint start --vm auto
curl -s localhost:4599/_feint/health | jq -c '.machines, .capabilities.isolation'

Sur la VM Debian 13 fraîchement installée, doctor annonce machine runtime: incus-ovn avec isolation true, et l'API de santé confirme "incus-ovn" puis true. Une valeur false signifie qu'OVN est absent, ou présent mais non câblé.

La machine porte-t-elle vraiment l'adresse publiée ?

Section intitulée « La machine porte-t-elle vraiment l'adresse publiée ? »

Oui, et cela se vérifie en trois commandes. Créez un réseau privé sur un bloc choisi, rattachez-y un serveur, démarrez-le, puis demandez au runtime, pas à l'émulateur, ce que la machine porte.

Fenêtre de terminal
# le bloc demandé est le bloc obtenu
curl -s -X POST "http://127.0.0.1:4599/vpc/v2/regions/fr-par/private-networks" \
-H 'Content-Type: application/json' \
-d '{"name":"lab","subnets":["10.51.0.0/24"]}' | jq -c '{id, subnet: .subnets[0].subnet}'
# ce que l'API publie
curl -s "http://127.0.0.1:4599/ipam/v1/regions/fr-par/ips" | jq -r '.ips[0].address'
# ce que la machine porte, vu du runtime
incus exec "feint-scw-<id-du-serveur>" -- ip -4 -o addr show

Sur mon poste, l'IPAM publie 10.51.0.2/24 et le conteneur porte 10.51.0.2/24 : les deux adresses coïncident. Le même essai en --vm incus-ovn donne 10.52.0.2/24 des deux côtés. La machine créée s'appelle feint-scw-<identifiant du serveur>, ce qui permet de la retrouver sans chercher.

Tout ce que l'émulateur crée est étiqueté, et feint clean retire exactement ces objets, sans toucher au reste de votre hôte :

Fenêtre de terminal
feint clean --vm incus
removed 1 machine(s), 1 network(s), 1 rule set(s)

Si Incus n'est pas encore installé sur votre poste, la section Incus du site couvre la mise en place.

feint snapshot nomme l'état d'un émulateur en cours et permet d'y revenir. C'est le mécanisme qui rend un jeu de données de test atteignable une fois puis rejouable autant de fois que nécessaire.

Fenêtre de terminal
feint snapshot save etat-de-reference
feint snapshot list
saved 21 resources to /home/bob/.local/state/feint/snapshots/etat-de-reference.json
NAME RESOURCES BYTES SAVED
etat-de-reference 21 26472 2026-07-30T09:43:40Z

Après avoir supprimé toutes les ressources, feint snapshot load etat-de-reference répond loaded etat-de-reference: the emulator now holds 21 resources et l'inventaire est reconstitué. Le chargement remplace l'état, il ne fusionne pas : un jeu de test ne doit pas dépendre de ce que la session a fait avant lui.

La couverture est partielle, et elle est mesurée plutôt qu'annoncée. En v0.2.0, 89 routes sont montées au total. Le tableau ci-dessous reprend la maturité déclarée par le projet et la part de la surface amont réellement servie :

FournisseurRoutes montéesSurface amont servieMaturitéProuvé par
Scaleway5527 %utilisablescw, Terraform, OpenTofu
Outscale207 %démarrageoapi-cli
Exoscale143 %aperçuexo

Utilisable signifie qu'une configuration réaliste s'applique et se détruit. Les deux autres niveaux veulent dire que le protocole est juste mais que la surface est mince. Concrètement, visez Scaleway pour un usage sérieux aujourd'hui, et considérez Outscale et Exoscale comme des chantiers ouverts.

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 :

Fenêtre de terminal
scw instance server create name=fantome type=DEV1-S \
image=00000000-dead-beef-0000-000000000000 zone=fr-par-1

C'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.

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 :

Fenêtre de terminal
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. Il écoute sur 127.0.0.1 par défaut, et c'est une décision de sécurité, pas un détail de configuration.

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.

SymptômeCauseSolution
404 Not Found sur scw instance server-type listLe CLI interroge /product-catalog/v2alpha1/, une API récente que l'émulateur ne monte pasUtiliser scw marketplace local-image list, ou consulter curl -s localhost:4599/_feint/routes
Feint does not serve /marketplace/v2/imagesLa route demandée n'existe pas dans le paquet ; le message le dit explicitementVérifier la route dans /_feint/routes avant d'insister
feint: no contract under contracts sur feint probeprobe a besoin des descriptions d'API livrées avec le dépôtLancer depuis le dépôt cloné, ou passer --contracts <répertoire>
warn no contracts/ directory here dans doctorMême cause, en avertissementSans effet si vous ne validez pas les réponses contre les contrats
gh attestation verify ne renvoie rienHors terminal interactif, la commande ne s'exprime que par son code retourContrôler echo $? ou ajouter --format json
timed out during banner exchange en SSH vers une machineUn ProxyJump du fichier ~/.ssh/config capture la plage 10.* des réseaux émulésRestreindre le motif Host, ou utiliser ssh -F /dev/null
Multiple variable sources detected avec TerraformUn profil Scaleway existe déjà sur le posteLire la colonne Currently using : le bloc provider l'emporte
Un mode --vm ne sépare pas deux VPCLe mode pont ne fournit pas l'isolationLire capabilities.isolation dans /_feint/health, et passer en --vm incus-ovn
  • feint émule Scaleway, Outscale et Exoscale sur un seul port, 127.0.0.1:4599, sans compte ni facture.
  • 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, eval suffit.
  • Terraform s'y branche avec api_url, et un cycle apply puis destroy complet passe.
  • Le mode machines est réel : le conteneur porte l'adresse publiée par l'API, et feint clean ne retire que ce que l'émulateur a créé.
  • Seul --vm incus-ovn isole deux VPC ; interrogez capabilities plutôt que de supposer.
  • feint version --check (depuis la 0.2.0) signale une nouvelle version et donne la commande épinglée ; FEINT_NO_UPDATE_CHECK=1 coupe tout appel réseau.
  • La couverture est partielle et assumée : 27 % de la surface Scaleway, 7 % chez Outscale, 3 % chez Exoscale.
  • Aucune signature n'est vérifiée : l'outil reste sur la boucle locale, jamais sur un réseau partagé.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn