{"id":13602076,"url":"https://github.com/89luca89/terrible","last_synced_at":"2025-05-16T19:07:24.850Z","repository":{"id":40352270,"uuid":"289074206","full_name":"89luca89/terrible","owner":"89luca89","description":"An Ansible playbook that applies the principle of the Infrastructure as Code on a QEMU/KVM environment.","archived":false,"fork":false,"pushed_at":"2024-11-24T16:55:28.000Z","size":1175,"stargazers_count":250,"open_issues_count":7,"forks_count":27,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-12T17:50:21.213Z","etag":null,"topics":["ansible","automation","debian","freebsd","iac","infrastructure","infrastructure-as-code","infrastructure-automation","kvm","kvm-server","libvirt","playbook","qemu","qemu-kvm","redhat","suse","terraform","terraform-libvirt","ubuntu"],"latest_commit_sha":null,"homepage":"","language":"YAML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/89luca89.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-20T17:59:59.000Z","updated_at":"2025-01-24T05:39:26.000Z","dependencies_parsed_at":"2024-12-04T04:00:43.915Z","dependency_job_id":null,"html_url":"https://github.com/89luca89/terrible","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/89luca89%2Fterrible","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/89luca89%2Fterrible/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/89luca89%2Fterrible/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/89luca89%2Fterrible/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/89luca89","download_url":"https://codeload.github.com/89luca89/terrible/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254592395,"owners_count":22097013,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","automation","debian","freebsd","iac","infrastructure","infrastructure-as-code","infrastructure-automation","kvm","kvm-server","libvirt","playbook","qemu","qemu-kvm","redhat","suse","terraform","terraform-libvirt","ubuntu"],"created_at":"2024-08-01T18:01:13.655Z","updated_at":"2025-05-16T19:07:24.831Z","avatar_url":"https://github.com/89luca89.png","language":"YAML","funding_links":[],"categories":["YAML","automation"],"sub_categories":[],"readme":"# Terrible: IaC for QEMU/KVM\n\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) ![Terraform Version](https://img.shields.io/badge/Terraform-v0.12-yellowgreen) ![Ansible Version](https://img.shields.io/badge/Ansible-v2.9%2B-yellowgreen) ![terraform_provider_libvirt](https://img.shields.io/badge/Terraform%20Provider%20Libvirt-v0.6-yellowgreen) ![Made_with_love](https://img.shields.io/badge/made%20with-%E2%9D%A4%EF%B8%8E-red)\n\n![logo](./pics/logo.png)\n\n### Workflows Status\n\n[![Ansible-Lint](https://github.com/89luca89/terrible/workflows/Ansible%20Lint/badge.svg)](https://github.com/89luca89/terrible/actions?query=workflow%3A%22Ansible+Lint%22)\n[![Terrible Validate](https://github.com/89luca89/terrible/workflows/Ansible%20Validate/badge.svg)](https://github.com/89luca89/terrible/actions?query=workflow%3A%22Ansible+Validate%22)\n[![Ansible Run](https://github.com/89luca89/terrible/actions/workflows/ansible-run.yml/badge.svg)](https://github.com/89luca89/terrible/actions/workflows/ansible-run.yml)\n\nThis **Ansible** playbook allows you to initialize and then deploy an entire infrastructure through the aid of **Terraform**, on a **QEMU/KVM** environment.\n\n**Terr**aform + Ans**ible**\n\n## Table of Contents\n\n1. [Abstract](#abstract)\n   - [Why not just use a single tool?](#why-not-just-use-a-single-tool)\n   - [How it works](#how-it-works)\n2. [Requirements](#requirements)\n3. [Configuration](#configuration)\n   - [Variables](#variables)\n   - [Terraform node, Bastions \u0026 Jumphosts](#terraform-node-bastions--jumphosts)\n   - [Network](#network)\n   - [Storage](#storage)\n4. [Compatibility](#compatibility)\n5. [Installation](#installation)\n   - [Container image](#container-image)\n6. [Usage](#usage)\n   - [Outputs](#outputs)\n7. [Authors](#authors)\n8. [License](#license)\n\n## Abstract\n\nThe Infrastructure as Code had considerable growth in the cloud lately.\nHowever, a separate discussion has to be done regarding the private cloud.\nFor various reasons, companies may need to use an internal infrastructure instead of cloud ones but,\nunfortunately, there aren't as many solutions fsuitable or the private cloud that most of the companies needs.\nOur main idea was to implement a flexible and powerful solution to build an infrastructure from scratch effortlessly.\nUsing the Ansible flexibility and the Terraform power allows users to abstract both the creation and the provisioning of the entire infrastructure,\ndescribing the whole process in a single file, easy to read and to maintain on the long run.\n\n### Why not just use a single tool?\n\nBy our side, the need to create a single source of truth for both the infrastructure creation and provisioning, lead to that choice.\nAs said, our objective was achievable thanks to the Ansible flexibility combined to Jinja2 simplicity that makes us capable of dynamically generating HCL files in order to leverage Terraform power and compatibility to build the infrastructure in no time.\n\n### How It Works\n\nThe basic idea comes from the complexity to automate VMs deployments in a QEMU/KVM environment.\n\nFor this reason we decided to automate the deployment process as much as possible, using **Ansible** and **Jinja2**.\n\nFirst of all we provided a basic **HCL** file (templated with **Jinja2**) describing a basic VM implementation. This is what is usually called IaC (Infrastructure as Code).\n\nThen by using Terraform and its amazing libvirt provider (https://github.com/dmacvicar/terraform-provider-libvirt), we can finally deploy the resultants HCL files generated by Ansible.\n\nThe figure below describes the process in an easier way.\n\n![![kvm-deployment]()](./pics/kvm-deployment.jpg)\n\nAs you can see, we start with the templated file (`terraform-vm.tf.j2`).\n\nWhen Ansible runs, it generates *n* `.tf` files, depending on the VM specified inside the inventory. This is the result of the initialization phase.\nOnce this task finished, the files are completed and ready to be used by Terraform.\n\nAt this time, Ansible takes those files and uses Terraform for each instance of them.\nOnce the task is finished, the VMs previously described into the inventory, will be correctly deployed into the QEMU/KVM server(s).\n\n## Requirements\n\n| Dependency   |      Minimum Version      | Reference |\n|----------|:-------------:|-------------|\n| Ansible |  2.9+ | https://docs.ansible.com/ |\n| Terraform |    0.12+   | https://www.terraform.io/docs/index.html |\n| Terraform Provider Libvirt | 0.6+ | https://github.com/dmacvicar/terraform-provider-libvirt/ |\n| Libvirt (on the target) | 1.2.14+ | https://libvirt.org/docs.html |\n\n## Configuration\n\nFirst of all you have to compose the inventory file in a right way. That means you have to describe the VMs you want to deploy into the server.\n\nAs you will see, there are some interesting variables you are allowed to use to properly describe your infrastructure.\nSome of them are `required` and some others are `optional`.\n\nBelow you can see the basic structure for the inventory.\n\n```yaml\nall:\n    vars:\n        ...\n    hosts:\n        terraform_node:\n            ...\n        hypervisor_1:\n            ...\n        hypervisor_2:\n            ...\n    children:\n        deploy:\n            vars:\n                pool_name: ...\n                ...\n            children:\n                group_1:\n                    hosts:\n                        host_1:\n                            ...\n                    vars:\n                        ...\n                group_2:\n                    hosts:\n                        host_2:\n                            ...\n                        host_3:\n                            ...\n                group_3:\n                    hosts:\n                        host_4:\n                            ...\n                    vars:\n                        ...\n                group_4:\n                    hosts:\n                        host_5:\n                            ...\n```\n\nUnder the 1st `vars` tag, you can specify the various hypervisors you want to use to distribute your infrastructure.\n\nHere's a little example:\n\n```yaml\nall:\n    hosts:\n        terraform_node:\n            ansible_host: 127.0.0.1\n            ansible_connection: local\n    vars:\n        ...\n    children:\n        deploy:\n            vars:\n                pool_name: default\n        ...\n```\n\nIn the above example, we specified the *uri* of the QEMU/KVM server (which is going to be common among all the VMs in this specific hypervisor group),\nthe storage *pool name* for the QEMU/KVM server and the `terraform node` address, which describes where Terraform is installed and where is going to being run.\n\nNow, for each VM we want to specify some property such as the number of the cpu(s), ram, network interfaces, etc.\n\nHere's a little example:\n\n```yaml\n        ...\nall:\n    hosts:\n        terraform_node:\n            ansible_host: 127.0.0.1\n            ansible_connection: local\n        hypervisor_1:\n            ansible_host: 127.0.0.1\n            ansible_connection: local\n    children:\n        deploy:\n            vars:\n                pool_name: default\n                disk_source: \"~/VirtualMachines/centos8-terraform.qcow2\"\n            children:\n                group_1:\n                    hosts:\n                        host_1:\n                            os_family: RedHat\n                            cpu: 4\n                            memory: 8192\n                            hypervisor: hypervisor_1\n                            network_interfaces:\n                                ...\n                group_2:\n                    hosts:\n                        host_2:\n                            os_family: RedHat\n                            cpu: 2\n                            hypervisor: hypervisor_1\n                        host_3:\n                            os_family: Suse\n                            disk_source: \"~/VirtualMachines/opensuse15.2-terraform.qcow2\"\n                            cpu: 4\n                            memory: 4096\n                            set_new_passowrd: password123\n                            hypervisor: hypervisor_1\n                            network_interfaces:\n                                ...\n```\n\nIn this example, we specified 2 main groups (`group_1`, `group_2`) and linked the VMs to `hypervisor_1`.\nThose groups are made of 3 VMs (`host_1`, `host_2`, `host_3`).\nAs you can see, not all the properties has been specified for each machine. This is posible due to the default variables value provided by this playbook.\n\nThanks to the variables hierarchy in Ansible, you can configure variables:\n\n- Hypervisor wise\n- VM group wise\n- Single VM wise\n\nThis will make easier to manage large homogeneous clusters, still retaining the power of per-VM customization.\n\n![Workflow](pics/workflow.png)\n\nIn the above example, we can see, for `hypervisor_1`, the default OS for the VMs is **Centos**, but we specified a different one for `host_3` a single **OpenSuse** node. Similarly for the `hypervisor_2`, the default OS for the VMs is **Ubuntu**, but we specified **Centos** for the `host_4` node.\n\nThis kind of configuration granularity is valid for any variable in the playbook.\n\nYou can check the default values under `default/main.yml`.\n\n### Variables\n\nOnce understood how to fill the inventory file, you are ready to check all the available variables to generate your infrastructure.\n\nThese variables are **required**:\n\n* **ansible_host:** `required`. Specifies the ip address for the VM. If not specified, a random ip is assigned.\n* **ansible_jump_hosts:** `required` if **terraform_bastion_enabled** is `True`. Specifies one or more jumphost/bastions for the ansible provisioning part.\n* **cloud_init**: `optional`. Specifies if the VM uses a cloud-init image or not. `False` If not specified.\n* **data_disks:** `optional`. Specifies additional disks to be added to the VM. Check disks section for internal required varibles: [HERE](#storage)\n* **disk_source:** `required`. Specifies the (local) path to the virtual disk you want to use to deploy the VMs.\n* **hypervisor:** `required`. Specifies on which hypervisor to deploy the Infrastructure.\n* **network_interfaces**: `required`. Specifies VM's network interfaces. Check network section for internal required variables: [HERE](#network)\n* **os_family:** `required`. Specifies the OS family for the installation. Possible values are: `RedHat`, `Debian`, `Suse`, `Alpine`, `FreeBSD`.\n* **pool_name:** `required`. Specifies the *storage pool* name where you want to deploy the VMs on the QEMU/KVM server.\n* **ssh_password:** `required`. Specifies the password to access the deployed VMs.\n* **ssh_port:** `required`. Specifies the port to access the deployed VMs.\n* **ssh_public_key_file:** `required`. Specifies the ssh public key file to deploy on the VMs.\n* **ssh_user:** `required`. Specifies the user to access the deployed VMs.\n\nAnsible hosts required outside the `deploy` group:\n\n* **terraform_node:** `required`. Specifies the the machine that performs the Terraform tasks.\n* **hypvervisor_[0-9+]:** `required`. Specifies the machine/machines that works as QEMU/KVM hypervisor (at least one machine needed).\nThe default value of 127.0.0.1 indicates that the machine that perform the Terraform tasks is the same that runs the Ansible playbook. In case the Terraform machine is not the localhost, you can specify the ip/hostname of the Terraform node. More details could be found here: [HERE](#terraform-node-bastions--jumphosts)\n\nThese variables are optional, there are sensible defaults set up, most of them can be declared from \u003cins\u003ehypervisor scope\u003c/ins\u003e to \u003cins\u003evm-group scope\u003c/ins\u003e and \u003cins\u003eper-vm scope\u003c/ins\u003e:\n\n* **change_passwd_command:** `optional`. Specifies a different command to be used to change the user's password. If not specified the default command is used. Default: `echo root:{{ set_new_password }} | chpasswd`. This variable become really useful when you are using a FreeBSD OS.\n* **cpu:** `optional`. Specifies the cpu number for the VM. If not specified, the default value is taken. Default: `1`\n* **memory:** `optional`. Specifies the memory ram for the VM. If not specified, the default value is taken. Default: `1024`\n* **set_new_password:** `optional`. Specifies a new password to access the Vm. If not specified, the default value (**ssh_password**) is taken.\n* **terraform_custom_provisioners**: `optional`. Specifies custom shell commands to run on newly created instances BEFORE ansible starts setting them up. Default `\"\"`\n* **terrible_custom_provisioners**: `optional`.  Specifies custom shell commands to run AFTER terrible run is completed (for example calling specific `ansible pull` for each node). Default `\"\"`\n* **vm_autoboot**: `optional`. Specifies if the VM should be automatically started at boot. Default: `False`\n* **base_deploy_path**: `optional`. Specifies where the Terraform files and state will be deployed, the default value is `$HOME`\n* **state_save_file**: `optional`. Specifies where the output terrible state is stored, the default value is `PATH_TO_THE_INVENTORY-state.tar.gz`\n\n\n### Terraform Node, Bastions \u0026 Jumphosts\n\nThe following section will describe some different deployment scenarios that we may tipically encounter.\n\nAs described above, the `terraform_node` variable is `required`.\nThe `terraform_node` could be local or remote.\n\nA really common scenario will have a local Terraform node. This could be declared as follows:\n\n```yaml\nall:\n    vars:\n        ...\n    hosts:\n        terraform_node:\n            ansible_host: 127.0.0.1\n            ansible_connection: local\n        hypervisor_1:\n            ansible_host: 127.0.0.1\n            ansible_connection: local\n```\n\nThis scenario assumes that the `terraform_node` is the same host that is running the Ansible playbook.\nThis case will ask Terraform to connect to QEMU/KVM using the uri `qemu:///system`.\n\n![local-all](./pics/local-all.png)\n\n---\n\nIf you want to use a remote QEMU/KVM server instead, you can do this:\n\n```yaml\nall:\n    vars:\n        ...\n    hosts:\n        terraform_node:\n          ansible_host: 127.0.0.1\n          ansible_connection: local\n        hypervisor_1:\n          ansible_host: remote_kvm_machine.domain\n          ansible_user: root\n          ansible_port: 22\n          ansible_ssh_pass: password\n```\nThis case will ask Terraform to connect to the QEMU/KVM server using the following uri: `qemu+ssh://root@remote_kvm_machine.domain/system`.\nThis also setup the Terraform internal ssh connection to use it as a **bastion** host to connect to his VMs.\n\n![remote-kvm](./pics/remote-kvm.png)\n\n---\n\nAlso, Terraform could be separated from Ansible and be located on a remote server.\nYou can declare it simply by using the `ansible_host` variable, as follows:\n\n```yaml\nall:\n    vars:\n        ...\n    hosts:\n        terraform_node:\n          ansible_host: remote_terraform_node.domain\n          ansible_connection: ssh # or paramiko or whatever NOT local\n        hypervisor_1:\n          ansible_host: remote_terraform_node.domain\n          ansible_connection: ssh # or paramiko or whatever NOT local\n          ansible_user: root\n          ansible_port: 22\n          ansible_ssh_pass: password\n```\nThis assumes that the `terraform_node` is the same host that is running the QEMU/KVM hypervisor.\nThis case will ask Terraform to connect to QEMU/KVM using the uri `qemu:///system`.\nThe *post-deployment* task of this Ansible playbook, has to use a **jumphost** to get access to the VMs of the internal network. For this reason we need to use the `terraform_node` as jumphost to reach them.\n\n![remote-terraform](./pics/remote-terraform.png)\n\n---\n\nAlso, if you have a remote QEMU/KVM server and a remote Terraform server, you can use them as follows:\n\n```yaml\nall:\n    vars:\n        ...\n    hosts:\n        terraform_node:\n          ansible_host: remote_terraform_node.test.com\n          ansible_connection: ssh # or paramiko or whatever NOT local\n        hypervisor_1:\n          ansible_host: remote_kvm_machine.domain\n          ansible_user: root\n          ansible_port: 22\n          ansible_ssh_pass: password\n```\nThis case will ask Terraform to connect to QEMU/KVM using the uri: `qemu+ssh://root@remote_kvm_machine.domain/system`.\nThis also setups the Terraform internal ssh connection to use it as a bastion to connect to its VMs.\nSince already remote, this case will set up 2 jumphosts for Ansible, first one is the `terraform_node`, the other\none is the `ansible_host`.\n\n![remote-all](./pics/remote-all.png)\n\n\n### Network\n\nNetwork declaration is \u003cins\u003emandatory and per-VM\u003c/ins\u003e.\n\nDeclare each device you want to add inside the `network_interfaces` dictionary.\n\n**Be aware that:**\n\n- \u003cins\u003ethe order of declaration is important\u003c/ins\u003e\n- the NAT device should \u003cins\u003ealways be present\u003c/ins\u003e (unless you can control your DHCP leases\n    for the external devices) and that should be the \u003cins\u003efirst\u003c/ins\u003e device.\n    It's an important parameter for the way the playbook has to communicate\n    with the VM \u003cins\u003ebefore\u003c/ins\u003e setting up all the userspace networks.\n- the `default_route` should be assigned to \u003cins\u003eone\u003c/ins\u003e interface to function properly. If not set it's equal to False.\n\nSupported interface types:\n\n* `nat`\n* `macvtap`\n* `bridge`\n\n\nStructure:\n\n```yaml\n        all:\n            vars:\n                pool_name: default\n                disk_source: \"~/VirtualMachines/centos8-terraform.qcow2\"\n            hosts:\n                terraform_node:\n                    ansible_host: 127.0.0.1\n                    ansible_connection: local\n                hypervisor_1:\n                    ansible_host: 127.0.0.1\n                    ansible_connection: local\n            children:\n                group_1:\n                    hosts:\n                        host_1:\n                            ansible_host: 172.16.0.155\n                            os_family: RedHat\n                            cpu: 4\n                            memory: 8192\n                            hypervisor: hypervisor_1\n                            network_interfaces:\n                                # Nat interface, it should always be the first one you declare.\n                                # it does not necessary have to be your default_route or main ansible_host,\n                                # but it's important to declare it so ansible has a way to communicate with\n                                # the VM and setup all the remaining networks.\n                                iface_1:\n                                  name: nat             # mandatory\n                                  type: nat             # mandatory\n                                  ip: 192.168.122.47    # mandatory\n                                  gw: 192.168.122.1     # mandatory\n                                  dns:                  # mandatory\n                                   - 1.1.1.1\n                                   - 8.8.8.8\n                                  mac_address: \"AA:BB:CC:11:24:68\"   # optional\n                                  # default_route: False\n                                iface_2:\n                                  name: ens1p0      # mandatory\n                                  type: macvtap     # mandatory\n                                  ip: 172.16.0.155  # mandatory\n                                  gw: 172.16.0.1    # mandatory\n                                  dns:              # optional\n                                   - 1.1.1.1\n                                   - 8.8.8.8\n                                  default_route: True # at least one true mandatory, false is optional.\n```\n\nVariables explanation:\n\n* **name:** `required` Specifies the name for the connection, this is important for `bridge` and `macvtap` types as it will be the interface/bridge on the host on which they will be created.\n* **type:** `required` Specifies interface type, supported types are **nat**, **macvtap**, **bridge**.\n* **ip:** `required` Specifies the IP to assign to this interface.\n* **gw:** `required` Specifies the Gateway of this interface.\n* **default_route:** `at least one required` Specifies if this interface is the default route or not. **At least one interface set as True**.\n* **dns:** `required` Specifies the dns list for this interface, this is an array of IPs.\n* **mac_address:** `optional` Specifies the mac address for this interface.\n\n\nThe playbook will use the available IP returned from the `terraform apply` command to access the machines\nand use the `os_family` way to setup the user-space part of the network:\n\n- static IPs\n- routes\n- gateways\n- DNS\n\nAfter that, the playbook will set the `ansible_host` variable to its original value, and proceed with\nthe provisioning.\n\nThis is important because it will make `ansible_host` independent from the internal management interface\nneeded for this network bootstrap tasks, making it easily compatible with any type of role that you\nwant to perform after that.\n\nDuring this process, virtual networks (bridges, VLANs, etc...) **inside the vm** will be ignored, this will improve detection\nof the networks we want to manage, improving compatibility with docker, k8s, nested-virtualization, etc...\n\n### Storage\n\nThis section explain how to add additional disks to the VMs.\n\nSuppose that you want to create a VM that needs a large amount of storage, and a separated disk just to store the configurations. This will be quite simple to achieve.\n\nThe main variable you need is `data_disks`, then you have to specify the disks and the related properties for each one.\n\nIf `data_disks` is mentioned in your inventory, the following variables are required:\n\n* **size:** `required`. Specifies the disk size expressed in GB. (eg. `size: 1` means 1GB)\n* **pool:** `required`. Specifies the pool where you want to store the additional disks.\n* **format:** `require`. Specifies the filesystem format you want to apply to the disk. Available filesystems are specified below.\n* **mount_point:** `required`. Specifies the mount point you want to create for the disk, use `none` if declaring a swap disk.\n* **encryption:** `required`. Specifies the mount point of the disk. Available values could be `True` or `False`.\n\n​\t**N.B.** Each disk declared must have a unique name (eg. you can't use `disk0` twice).\n\n| OS Family   |  Supported Disk Format      |  Encryption Supported  |\n|----------|:-------------|--------------|\n| Debian |  `ext2`, `ext3`, `ext4`, `swap` | yes |\n| Alpine |  `ext2`, `ext3`, `ext4`, `swap` | yes |\n| FreeBSD |  `ufs`, `swap`     |  no  |\n| RedHat | `ext2`, `ext3`, `ext4`, `xfs`, `swap` | yes |\n| Suse | `ext2`, `ext3`, `ext4`, `xfs`, `swap` | yes |\n\nLet's take a look at how the *inventory* file is going to be fill.\n\n```yaml\n        all:\n            vars:\n                pool_name: default\n                disk_source: \"~/VirtualMachines/centos8-terraform.qcow2\"\n            hosts:\n                terraform_node:\n                    ansible_host: 127.0.0.1\n                    ansible_connection: local\n                hypervisor_1:\n                    ansible_host: 127.0.0.1\n                    ansible_connection: local\n            children:\n                group_1:\n                    hosts:\n                        host_1:\n                            ansible_host: 172.16.0.155\n                            os_family: RedHat\n                            cpu: 4\n                            memory: 8192\n                            hypervisor: hypervisor_1\n                            # Here we start to declare\n                            # the additional disk.\n                            data_disks:\n                                # Here we declare the disk name\n                            \tdisk-storage: disk0                 # Uniqe name to identify the disk unit.\n                            \t\tsize: 100                       # Disk size = 100 GB\n                            \t\tpool: default                   # Store the disk image into the pool = default.\n                            \t\tformat: xfs                     # Disk Filesystem = xfs\n                            \t\tmount_point: /mnt/data_storage  # The path where the disk is mounted, none is using swap\n                            \t\tencryption: True                # Enable disk encryption\n\n                                # Here we declare the disk name\n                            \tdisk-swap: swp0                     # Uniqe name to identify the disk unit.\n                            \t\tsize: 1                         # Disk size = 1 GB\n                            \t\tpool: default                   # Store the disk image into the pool = default.\n                            \t\tformat: swap                    # Disk Filesystem = swap\n                            \t\tmount_point: none               # The path where the disk is mounted, none if using swap\n                            \t\tencryption: False               # Does not enable disk encryption\n```\n\n\n\n## Compatibility\n\nAt this time the playbook supports the most common 4 OS families for the Guests:\n\n* Alpine\n* RedHat\n    * RedHat7\n    * RedHat8\n    * Centos7\n    * Centos8\n    * RockyLinux\n    * Almalinux\n    * Fedora and derivatives ( **untested** )\n* Debian\n    * Debian 9\n    * Debian 10\n    * Ubuntu 18\n    * Ubuntu 20\n    * Other derivatives ( **untested** )\n* Suse\n    * Leap\n    * Thumbleweed\n    * Other derivatives ( **untested** )\n* FreeBSD\n    * FreeBSD 12.x\n    * FreeBSD 13.x\n    * Other derivatives ( **untested** )\n\nThis means you'll be able to generate the infrastructure using **ONLY** the OS listed above.\n\nHypervisor OS is agnostic, as long as requirements are met.\n\n## Installation\n\nBefore using **Terrible**, the following system dependencies needs to be installed: [dependencies](#requirements).\n\nUse the following command to satisfy the project dependencies:\n\n```bash\npip3 install --user -r requirements.txt\n```\n\n### Container Image\n\nTo avoid boring dependencies installation to make Terrible works and speed up your infrastructure deployment, we provided a `Dockerfile` to build yourself a minimal image with all you need.\n\nWe use a `debian:buster-slim` image to have a compact system, fully compatibile with all the required tools. The container image uses the latest Terrible tag's release.\n\nThe minimum packages required to run the container image is **Docker (or Podman)** and **QEMU/KVM** installed on the system.\n\n#### Pull\n\nIf you are a lazy person (just like us), you can directly pull the latest image release from DockerHub.\n\n```bash\ndocker pull 89luca89/terrible:latest\n```\n\n#### Build\n\nTo build the image, instead, type the following command:\n\n```bash\ndocker build -t terrible .\n```\n\nThis will take some time, grab a cup of coffee and wait.\n\n#### Run\n\nOnce you've built the image, you're ready to run it as in the example below:\n\n```bash\ndocker run \\\n    -it \\\n    --rm \\\n    -v /var/run/libvirt/libvirt-sock:/var/run/libvirt/libvirt-sock \\\n    -v ./inventory-test.yml:/terrible/inventory-test.yml \\\n    -v /path/to/vm/images/:/opt/ \\\n    -v ~/.ssh/:/root/.ssh/ \\\n    89luca89/terrible\n```\n\n**N.B.** If you are using RHEL, CentOS or Fedora you need to add the `--privileged` flag because otherwise SELinux does not allow it to access the libvirt socket.\n\n**N.B.** If you are using your local QEMU/KVM instance, remember to add `--net=host` to the command.\n\n**Notes:**\n\n* The volume `/var/run/libvirt/libvirt-sock` is mandatory if you want to run Terrible locally (a local QEMU/KVM instance). In this way you'll directly interact with the QEMU/KVM api, provided by the system.\n\n* The volume `./inventory-test.yml` has to include the inventory file inside the container, to deploy the infrastructure.\n\n* The volume `~/VirtualMachines/` has to include the `qcow2` images inside the container to deploy them.\n* The volume `~/.ssh` has to include your ssh keys into the container to deploy them inside the infrastructure machines.\n\n## Usage\n\nTo speed up your deployment process, we made our Packer template files available.\n\nThe other repository could be found here: [packer-terraform-kvm](https://github.com/89luca89/packer-terraform-kvm).\n\nOnce composed the inventory file, it's time to run your playbook.\n\nTo pull up infrastructure:\n\n```bash\nansible-playbook -i inventory.yml -u root main.yml\n```\n\nTo validate the inventory file:\n\n```bash\nansible-playbook -i inventory.yml -u root main.yml --tags validate\n```\n\nTo pull down infrastructure (maintaining the resources in place):\n\n```bash\nansible-playbook -i inventory.yml -u root main.yml --tags destroy\n```\n\nTo completely delete the infrastructure:\n\n```bash\nansible-playbook -i inventory.yml -u root main.yml --tags purge\n```\n\n### Outputs\n\nBased on your inventory, the complete state of the infrastructure (TF files, TF states, LUKS keys etc...)\nwill be written to `${INVENTORY_NAME}-state.tar.gz` this file is essential to keep track of the\ninfrastructure state.\n\nYou can (and should) save this state file to keep track of the infrastructure complete state, the *.tar.gz\nwill be restored and saved on each run.\n\n## Authors\n\n- Luca Di Maio      \u003cluca.dimaio1@gmail.com\u003e\n- Alessio Greggi    \u003cgreggialessio@gmail.com\u003e\n\n## License\n\n- GNU GPLv3, See LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F89luca89%2Fterrible","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F89luca89%2Fterrible","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F89luca89%2Fterrible/lists"}