La stack technique en détail

1. Packer : Création du template VM

Packer nous permet de créer une image VM standardisée qui servira de base pour notre serveur GNS3.

J'ai configuré ma template avec ces spécifications :

L'objectif est simple : une fois la VM déployée, je peux y accéder soit :

Ces deux paramètres ont déjà été configurés sur le reverse proxy (Traefik) et le DNS (PowerDNS).

Configuration existante :
Dans PowerDNS, nous avons les enregistrements DNS suivants :gns3.reverse9.xyz -> A: 10.10.10.249/24webui.gns3.reverse9.xyz -> CNAME : traefik.reverse9.xyz -> A: 10.10.10.231

Dans Traefik, une configuration permet la redirection suivante :https://webui.gns3.reverse9.xyz -> http://gns3.reverse9.xyz:3080

Ce qui donne le schéma suivant :

Au lancement de la pipeline CI/CD, GitLab utilise le runner installé sur la VM "Provisionner" (où sont installés tous les outils) comme intermédiaire pour piloter les différents outils. Le processus se déroule comme suit :

  1. Le runner utilise Packer pour créer le template sur le cluster Proxmox
  2. Terraform clone ce template pour créer une nouvelle VM et la configure (réseau, utilisateur, clé SSH, etc.)

Ansible installe Docker et le serveur GNS3 à l'aide de deux playbooks dédiés

Note : Docker doit être installé au préalable : une erreur bloque l’installation de GNS3 via Ansible, bien que le script fonctionne manuellement

Configuration Packer détaillée

packer {
  required_plugins {
    proxmox = {
      version = "~> 1"
      source  = "github.com/hashicorp/proxmox"
    }
  }
}

source "proxmox-iso" "ubuntu-server-noble" {
  # Configuration Proxmox
  node                 = "pve"
  vm_id                = "555"
  vm_name              = "gns3-template"
  template_description = "GNS3VM Template from packer for Terraform"

  # Configuration matérielle
  cores   = "10"
  memory  = "49152"  # 48 GB
  disks {
    disk_size    = "400G"
    format       = "raw"
    storage_pool = "SSDK"
    type         = "virtio"
  }

  # Configuration réseau
  network_adapters {
    model    = "virtio"
    bridge   = "vmbr0"
    firewall = "false"
  }

  # Configuration Cloud-Init
  cloud_init              = true
  cloud_init_storage_pool = "local"
}

Cette configuration définit :

Configuration Cloud-Init pour Packer

#cloud-config
fqdn: gns3.reverse9.xyz
hostname: gns3vm
preserve_hostname: true
autoinstall:
  version: 1
  locale: en_US
  keyboard:
    layout: fr
  ssh:
    install-server: true
    allow-pw: true
    disable_root: true
    ssh_quiet_keygen: true
    allow_public_ssh_keys: true
  packages:
    - qemu-guest-agent
    - sudo
  storage:
    layout:
      name: direct
    swap:
      size: 0
  user-data:
    package_upgrade: false
    timezone: Indian/Reunion
    users:
      - name: admin
        groups: [adm, sudo]
        lock-passwd: false
        sudo: ALL=(ALL) NOPASSWD:ALL
        shell: /bin/bash
        ssh_authorized_keys:
           - # Votre clé publique SSH

Cette configuration Cloud-Init :

2. Terraform : Déploiement automatisé

Configuration Infisical Provider

terraform {
  required_providers {
    proxmox = {
      source = "bpg/proxmox"
      version = "0.42.0"
    }  
    infisical = {
      source = "infisical/infisical"
    }
  }
}

provider "infisical" {
  host = "https://infisical.reverse9.xyz/"
  client_id = var.infisical_client_id
  client_secret = var.infisical_client_secret
}

Cette configuration :

Récupération des secrets

ephemeral "infisical_secret" "proxmox_endpoint" {
  name         = "PROXMOX_ENDPOINT"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

ephemeral "infisical_secret" "proxmox_api_token" {
  name         = "PROXMOX_API_TOKEN"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

Cette partie :

Configuration de la VM

resource "proxmox_virtual_environment_vm" "vm" {
  name      = var.vm_hostname
  node_name = var.target_node

  cpu {
    type = "host"
    cores = 10
  }

  clone {
    vm_id = var.source_vm_id
    full  = true
  }

  network_device {
    model    = "virtio"
    bridge   = var.proxmox_bridge
    vlan_id  = var.vm_vlan_id
  }

  initialization {
    datastore_id = "SSDK"
    user_data_file_id = proxmox_virtual_environment_file.cloud_user_config.id
    ip_config {
      ipv4 {
        address = "${var.ip_address}/${var.netmask}"
        gateway = var.gateway
      }
    }
  }
}

Cette configuration :

Cloud-Init pour Terraform

#cloud-config
hostname: gns3vm
fqdn: gns3.reverse9.xyz
users:
  - name: ${username}
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - ${ssh_key}

network:
  version: 2
  ethernets:
    eth0:
      nameservers:
        addresses: [10.10.10.246]
        search: [reverse9.xyz]

Cette configuration :

Les secrets sont gérés dans Infisical avec une organisation "Projets", et dans les projets, j'ai des dossiers par outil.

Projet : gns3-autosetup
├── Packer
│   ├── Tous les secrets de Packer
└── Terraform
    └── Tous les secrets de Terraform

Les secrets sont structurés de la manière suivante dans l'application :

On retrouve le projet
Puis les dossiers pour chaque outil
Et enfin les secrets. Ici dans cet exemple les secrets de Packer

Note : On remarque la possibilité de définir différents secrets selon les environnements (Dev, Staging ou Pré-Prod, Prod)

3. Ansible : Installation et configuration

Installation de Docker

- name: Install docker
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download docker install script
      ansible.builtin.get_url:
        url: https://get.docker.com
        dest: /tmp/get-docker.sh
        mode: '0755'

    - name: Run docker install script
      ansible.builtin.command: sh /tmp/get-docker.sh

Ce playbook :

Installation de GNS3

- name: Install GNS3 with required components
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download GNS3 remote install script
      ansible.builtin.get_url:
        url: https://raw.githubusercontent.com/GNS3/gns3-server/master/scripts/remote-install.sh
        dest: /tmp/gns3-remote-install.sh
        mode: '0755'

    - name: Execute GNS3 installation script
      ansible.builtin.command: bash /tmp/gns3-remote-install.sh --with-iou --with-i386-repository

Ce playbook :

4. GitLab CI/CD : Orchestration

stages:
  - build
  - deploy
  - configure

variables:
  GIT_DEPTH: "1"

build_template:
  stage: build
  script:
    - echo "Building the VM template with Packer..."
    - chmod +x Packer/packer-entrypoint.sh
    - ./Packer/packer-entrypoint.sh

deploy_infrastructure:
  stage: deploy
  script:
    - echo "Deploying infrastructure with Terraform..."
    - chmod +x Terraform/terraform-entrypoint.sh
    - ./Terraform/terraform-entrypoint.sh build
  artifacts:
    paths:
      - Terraform/terraform.tfstate
    expire_in: 1 hour
  dependencies:
    - build_template

configure_vm:
  stage: configure
  script:
    - echo "Configuring VM with Ansible (Docker + GNS3)..."
    - chmod +x Ansible/ansible-entrypoint.sh
    - ./Ansible/ansible-entrypoint.sh
  dependencies:
    - deploy_infrastructure

Cette pipeline :

  1. Crée le template avec Packer
  2. Déploie l'infrastructure avec Terraform
  3. Configure la VM avec Ansible
  4. Conserve le tfstate comme artifact

On voit donc les étapes de la pipeline :

Le processus de déploiement en détail

1. Création du template (Packer)

Le processus commence avec Packer qui :

  1. Télécharge l'ISO Ubuntu 24.04
  2. Crée une VM sur Proxmox avec :
    • Configuration matérielle optimisée pour GNS3
    • Cloud-Init activé
  3. Installe le système avec :
    • Les packages de base
    • L'agent QEMU
    • La configuration SSH
  4. Prépare le template pour Terraform

2. Déploiement de l'infrastructure (Terraform)

Terraform prend le relais pour :

  1. Récupérer les credentials depuis Infisical :
    • Endpoint Proxmox
    • Token API
    • Configurations sensibles
  2. Créer une nouvelle VM avec :
    • Clone du template
    • Configuration réseau personnalisée
    • Initialisation Cloud-Init
  3. Préparer la VM pour Ansible avec :
    • Configuration DNS
    • Accès SSH (user:publickey)

3. Configuration du serveur GNS3 (Ansible)

Finalement, Ansible :

  1. Installe Docker :
    • Configuration du repository
    • Installation des dépendances
    • Configuration du daemon
  2. Installe GNS3 :
    • Composants serveur
    • Support IOU
    • Dépendances système

Conclusion

Cette solution d'automatisation me permet de :

Le code source complet est disponible sur GitHub

La topologie n'est pas complexe, mais on peut voir que GNS3 fonctionne parfaitement.

Pourquoi réinventer la roue ?

Après avoir fait tout cela, on peut se poser la question : pourquoi ne pas avoir simplement converti l'OVA GNS3 fourni par l'éditeur et importé le disque sur une VM dans Proxmox ?

Pour répondre à cette question, je vais peser le pour et le contre des deux approches.

Convertir la VM et l'importer

Avantages

Dans les grandes lignes, il suffit de :

  1. Télécharger la VM depuis le site de GNS3
  2. Décompresser l'archive obtenue
  3. Créer une VM sur Proxmox
  4. Convertir le VMDK en QCOW2
  5. Importer le disque sur une VM

Inconvénients

Stack CI/CD

Avantages CI/CD

Références

Quelques liens utilisés pour cet article

Templates Proxmox avec Packer et Ansible
Automatisez vos templates Proxmox avec Packer et Ansible pour une infrastructure virtuelle agile et sécurisée. Découvrez comment optimiser votre déploiement.
Gérez vos secrets avec Infisical
Comment protéger vos secrets avec la plateforme de gestion de secrets Infisical?
Infrastructure Automation: Provisioning VMs on Proxmox with Packer, OpenTOFU, GitLab, Vault, and…
Infrastructure as Code (IaC) and Continuous Integration/Continuous Delivery (CI/CD) pipelines reign supreme in today’s DevOps landscape…
" >

Automatisation du déploiement d'une VM GNS3 sur Proxmox

Automatisation du déploiement d'une VM GNS3 sur Proxmox

Pendant mes études, j'ai eu besoin de déployer des VMs GNS3 sur mon cluster Proxmox. Pour rendre ce processus plus efficace, j'ai mis en place une solution complète d'automatisation qui utilise plusieurs outils DevOps modernes :

  • Packer pour la création d'images
  • Terraform pour le provisionnement d'infrastructure
  • Ansible pour l'installation et la configuration des services
  • Infisical pour la gestion des secrets
  • GitLab CI/CD pour l'automatisation

Ce qui m'a particulièrement plu dans cette approche, c'est que tout est automatisé :

  • L'image de base est créée automatiquement avec ma configuration (pas besoin de télécharger une ISO d'Ubuntu, de l'installer et de la configurer)
  • Le déploiement se fait en un clic grâce à la pipeline CI/CD
  • Les secrets sont gérés de manière sécurisée et centralisée
  • La configuration réseau est flexible et adaptable selon les besoins
  • Le tout est reproductible à l'identique
Rappel : GNS3 est un logiciel libre permettant l'émulation ou la simulation de réseaux informatiques.

La stack technique en détail

1. Packer : Création du template VM

Packer nous permet de créer une image VM standardisée qui servira de base pour notre serveur GNS3.

J'ai configuré ma template avec ces spécifications :

  • CPU : 10 cœurs (nécessaire pour la virtualisation imbriquée)
  • RAM : 48 GB (pour gérer plusieurs machines virtuelles)
  • Disque : 400 GB (stockage des images et machines virtuelles)
  • OS : Ubuntu 24.04 (Noble)
  • Réseau : Configuration réseau précise
    • VLAN : 10
    • Adresse IP : 10.10.10.249/24 (permet de fonctionner avec le reverse proxy / FQDN déjà déployé)

L'objectif est simple : une fois la VM déployée, je peux y accéder soit :

Ces deux paramètres ont déjà été configurés sur le reverse proxy (Traefik) et le DNS (PowerDNS).

Configuration existante :
Dans PowerDNS, nous avons les enregistrements DNS suivants :gns3.reverse9.xyz -> A: 10.10.10.249/24webui.gns3.reverse9.xyz -> CNAME : traefik.reverse9.xyz -> A: 10.10.10.231

Dans Traefik, une configuration permet la redirection suivante :https://webui.gns3.reverse9.xyz -> http://gns3.reverse9.xyz:3080

Ce qui donne le schéma suivant :

Au lancement de la pipeline CI/CD, GitLab utilise le runner installé sur la VM "Provisionner" (où sont installés tous les outils) comme intermédiaire pour piloter les différents outils. Le processus se déroule comme suit :

  1. Le runner utilise Packer pour créer le template sur le cluster Proxmox
  2. Terraform clone ce template pour créer une nouvelle VM et la configure (réseau, utilisateur, clé SSH, etc.)

Ansible installe Docker et le serveur GNS3 à l'aide de deux playbooks dédiés

Note : Docker doit être installé au préalable : une erreur bloque l’installation de GNS3 via Ansible, bien que le script fonctionne manuellement

Configuration Packer détaillée

packer {
  required_plugins {
    proxmox = {
      version = "~> 1"
      source  = "github.com/hashicorp/proxmox"
    }
  }
}

source "proxmox-iso" "ubuntu-server-noble" {
  # Configuration Proxmox
  node                 = "pve"
  vm_id                = "555"
  vm_name              = "gns3-template"
  template_description = "GNS3VM Template from packer for Terraform"

  # Configuration matérielle
  cores   = "10"
  memory  = "49152"  # 48 GB
  disks {
    disk_size    = "400G"
    format       = "raw"
    storage_pool = "SSDK"
    type         = "virtio"
  }

  # Configuration réseau
  network_adapters {
    model    = "virtio"
    bridge   = "vmbr0"
    firewall = "false"
  }

  # Configuration Cloud-Init
  cloud_init              = true
  cloud_init_storage_pool = "local"
}

Cette configuration définit :

  • Les plugins requis pour Proxmox
  • Les spécifications matérielles de la VM
  • La configuration réseau
  • L'activation de Cloud-Init pour la configuration post-déploiement

Configuration Cloud-Init pour Packer

#cloud-config
fqdn: gns3.reverse9.xyz
hostname: gns3vm
preserve_hostname: true
autoinstall:
  version: 1
  locale: en_US
  keyboard:
    layout: fr
  ssh:
    install-server: true
    allow-pw: true
    disable_root: true
    ssh_quiet_keygen: true
    allow_public_ssh_keys: true
  packages:
    - qemu-guest-agent
    - sudo
  storage:
    layout:
      name: direct
    swap:
      size: 0
  user-data:
    package_upgrade: false
    timezone: Indian/Reunion
    users:
      - name: admin
        groups: [adm, sudo]
        lock-passwd: false
        sudo: ALL=(ALL) NOPASSWD:ALL
        shell: /bin/bash
        ssh_authorized_keys:
           - # Votre clé publique SSH

Cette configuration Cloud-Init :

  • Configure le hostname et le FQDN
  • Met en place l'accès SSH sécurisé
  • Installe les packages essentiels
  • Crée un utilisateur admin avec les droits sudo

2. Terraform : Déploiement automatisé

Configuration Infisical Provider

terraform {
  required_providers {
    proxmox = {
      source = "bpg/proxmox"
      version = "0.42.0"
    }  
    infisical = {
      source = "infisical/infisical"
    }
  }
}

provider "infisical" {
  host = "https://infisical.reverse9.xyz/"
  client_id = var.infisical_client_id
  client_secret = var.infisical_client_secret
}

Cette configuration :

  • Définit les providers nécessaires (ici Proxmox)
  • Configure l'accès à Infisical pour la gestion des secrets

Récupération des secrets

ephemeral "infisical_secret" "proxmox_endpoint" {
  name         = "PROXMOX_ENDPOINT"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

ephemeral "infisical_secret" "proxmox_api_token" {
  name         = "PROXMOX_API_TOKEN"
  env_slug     = "prod"
  workspace_id = "8732dcc5-9548-4466-b2db-e837aecc54de"
  folder_path  = "/Terraform"
}

Cette partie :

  • Récupère les credentials Proxmox depuis Infisical
  • Utilise des secrets éphémères pour plus de sécurité (pas de trace de credentials dans les tfstates)

Configuration de la VM

resource "proxmox_virtual_environment_vm" "vm" {
  name      = var.vm_hostname
  node_name = var.target_node

  cpu {
    type = "host"
    cores = 10
  }

  clone {
    vm_id = var.source_vm_id
    full  = true
  }

  network_device {
    model    = "virtio"
    bridge   = var.proxmox_bridge
    vlan_id  = var.vm_vlan_id
  }

  initialization {
    datastore_id = "SSDK"
    user_data_file_id = proxmox_virtual_environment_file.cloud_user_config.id
    ip_config {
      ipv4 {
        address = "${var.ip_address}/${var.netmask}"
        gateway = var.gateway
      }
    }
  }
}

Cette configuration :

  • Clone le template créé par Packer
  • Configure les ressources CPU
  • Met en place le réseau avec VLAN
  • Initialise la VM avec Cloud-Init

Cloud-Init pour Terraform

#cloud-config
hostname: gns3vm
fqdn: gns3.reverse9.xyz
users:
  - name: ${username}
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    ssh_authorized_keys:
      - ${ssh_key}

network:
  version: 2
  ethernets:
    eth0:
      nameservers:
        addresses: [10.10.10.246]
        search: [reverse9.xyz]

Cette configuration :

  • Définit les paramètres réseau
  • Configure les DNS
  • Met en place l'utilisateur avec sa clé SSH

Les secrets sont gérés dans Infisical avec une organisation "Projets", et dans les projets, j'ai des dossiers par outil.

Projet : gns3-autosetup
├── Packer
│   ├── Tous les secrets de Packer
└── Terraform
    └── Tous les secrets de Terraform

Les secrets sont structurés de la manière suivante dans l'application :

On retrouve le projet
Puis les dossiers pour chaque outil
Et enfin les secrets. Ici dans cet exemple les secrets de Packer

Note : On remarque la possibilité de définir différents secrets selon les environnements (Dev, Staging ou Pré-Prod, Prod)

3. Ansible : Installation et configuration

Installation de Docker

- name: Install docker
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download docker install script
      ansible.builtin.get_url:
        url: https://get.docker.com
        dest: /tmp/get-docker.sh
        mode: '0755'

    - name: Run docker install script
      ansible.builtin.command: sh /tmp/get-docker.sh

Ce playbook :

  • Télécharge le script d'installation Docker
  • Exécute l'installation de manière automatisée

Installation de GNS3

- name: Install GNS3 with required components
  hosts: vlan10_infra
  become: yes
  tasks:
    - name: Download GNS3 remote install script
      ansible.builtin.get_url:
        url: https://raw.githubusercontent.com/GNS3/gns3-server/master/scripts/remote-install.sh
        dest: /tmp/gns3-remote-install.sh
        mode: '0755'

    - name: Execute GNS3 installation script
      ansible.builtin.command: bash /tmp/gns3-remote-install.sh --with-iou --with-i386-repository

Ce playbook :

  • Installe GNS3 avec ses composants
  • Active le support IOU
  • Configure les dépôts nécessaires

4. GitLab CI/CD : Orchestration

stages:
  - build
  - deploy
  - configure

variables:
  GIT_DEPTH: "1"

build_template:
  stage: build
  script:
    - echo "Building the VM template with Packer..."
    - chmod +x Packer/packer-entrypoint.sh
    - ./Packer/packer-entrypoint.sh

deploy_infrastructure:
  stage: deploy
  script:
    - echo "Deploying infrastructure with Terraform..."
    - chmod +x Terraform/terraform-entrypoint.sh
    - ./Terraform/terraform-entrypoint.sh build
  artifacts:
    paths:
      - Terraform/terraform.tfstate
    expire_in: 1 hour
  dependencies:
    - build_template

configure_vm:
  stage: configure
  script:
    - echo "Configuring VM with Ansible (Docker + GNS3)..."
    - chmod +x Ansible/ansible-entrypoint.sh
    - ./Ansible/ansible-entrypoint.sh
  dependencies:
    - deploy_infrastructure

Cette pipeline :

  1. Crée le template avec Packer
  2. Déploie l'infrastructure avec Terraform
  3. Configure la VM avec Ansible
  4. Conserve le tfstate comme artifact

On voit donc les étapes de la pipeline :

Le processus de déploiement en détail

1. Création du template (Packer)

Le processus commence avec Packer qui :

  1. Télécharge l'ISO Ubuntu 24.04
  2. Crée une VM sur Proxmox avec :
    • Configuration matérielle optimisée pour GNS3
    • Cloud-Init activé
  3. Installe le système avec :
    • Les packages de base
    • L'agent QEMU
    • La configuration SSH
  4. Prépare le template pour Terraform

2. Déploiement de l'infrastructure (Terraform)

Terraform prend le relais pour :

  1. Récupérer les credentials depuis Infisical :
    • Endpoint Proxmox
    • Token API
    • Configurations sensibles
  2. Créer une nouvelle VM avec :
    • Clone du template
    • Configuration réseau personnalisée
    • Initialisation Cloud-Init
  3. Préparer la VM pour Ansible avec :
    • Configuration DNS
    • Accès SSH (user:publickey)

3. Configuration du serveur GNS3 (Ansible)

Finalement, Ansible :

  1. Installe Docker :
    • Configuration du repository
    • Installation des dépendances
    • Configuration du daemon
  2. Installe GNS3 :
    • Composants serveur
    • Support IOU
    • Dépendances système

Conclusion

Cette solution d'automatisation me permet de :

  • Déployer un nouveau serveur GNS3 en quelques minutes
  • Garantir une configuration cohérente et reproductible
  • Gérer les secrets de manière sécurisée et centralisée
  • Maintenir facilement l'infrastructure avec des outils modernes

Le code source complet est disponible sur GitHub

La topologie n'est pas complexe, mais on peut voir que GNS3 fonctionne parfaitement.

Pourquoi réinventer la roue ?

Après avoir fait tout cela, on peut se poser la question : pourquoi ne pas avoir simplement converti l'OVA GNS3 fourni par l'éditeur et importé le disque sur une VM dans Proxmox ?

Pour répondre à cette question, je vais peser le pour et le contre des deux approches.

Convertir la VM et l'importer

Avantages

  • Gain de temps immense : pas besoin de se casser la tête à créer des playbooks Ansible, des configurations Terraform, un template Packer
  • Simplicité : en 2 commandes, c'est terminé

Dans les grandes lignes, il suffit de :

  1. Télécharger la VM depuis le site de GNS3
  2. Décompresser l'archive obtenue
  3. Créer une VM sur Proxmox
  4. Convertir le VMDK en QCOW2
  5. Importer le disque sur une VM

Inconvénients

  • Perte de flexibilité
    • Impossible de personnaliser la configuration réseau (VLAN, IP, identifiants) avant le déploiement
  • Apprentissage limité
    • La conversion de formats de disque virtuel est une compétence basique

Stack CI/CD

Avantages CI/CD

  • Personnalisation complète
  • Reproductibilité garantie
  • Gestion des secrets sécurisée
  • Apprentissage des outils DevOps modernes :
    • Packer
    • Terraform
    • Ansible
    • GitLab CI/CD

Références

Quelques liens utilisés pour cet article

Templates Proxmox avec Packer et Ansible
Automatisez vos templates Proxmox avec Packer et Ansible pour une infrastructure virtuelle agile et sécurisée. Découvrez comment optimiser votre déploiement.
Gérez vos secrets avec Infisical
Comment protéger vos secrets avec la plateforme de gestion de secrets Infisical?
Infrastructure Automation: Provisioning VMs on Proxmox with Packer, OpenTOFU, GitLab, Vault, and…
Infrastructure as Code (IaC) and Continuous Integration/Continuous Delivery (CI/CD) pipelines reign supreme in today’s DevOps landscape…