Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Feature: allow specifying of target host machine on every individual resource/data source #1071

Open
memetb opened this issue Feb 22, 2024 · 0 comments

Comments

@memetb
Copy link

memetb commented Feb 22, 2024

System Information

Linux distribution

any

Terraform version

terraform -v

Terraform v1.5.7
on linux_amd64

Provider and libvirt versions

git describe --always --abbrev=40 --dirty

c8facd868b69360f4542f8907eb1cf4c7b2fffa8-dirty

Description of Issue/Question

The current recommendation for connecting to multiple hosts is to declare multiple providers and assign them aliases. Indeed, this is how hashicorp themselves recommend using multiple providers with AWS.

However, AWS is a service, where as libvirt is connecting directly to machines and therefore the use case is not exactly the same. Let's take for instance an enterprise which collocates multiple racks in multiple geographic locations (TOR,NYC,SFC). Each rack has an id (rackN), and in each rack there are 5 general purpose compute machines (generalN), 3 GPU enabled machines (gpuN), and 3 storage servers (storageN) with dedicated connectivity between. This gives each server a fqdn slug like tor-rack1-general2.evilcorp.com.

Now let's say an IaC engineer wants to create a module for an application that will allocate allocate a CPU frontend and a GPU backend, and allocate a storage device on the storage server.

The desired use-case for such a module would be something like so:

terraform {
  required_version = ">= 0.13"
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
      version = "1.0.0"
    }
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

provider "digitalocean" {
  token = var.do_token
}

provider "cloudflare" {
  api_token = var.cf_token
}

provider "libvirt" {
  uri = "qemu+ssh://${var.target}/system?sshauth=privkey&no_verify=true"
}

module "dev" {
  source = "./foobar"

  region   = "TOR"
  hostname = "development"
  //...
}

module "uat" {
  source = "./foobar"

  region   = "TOR"
  hostname = "user-acceptance"
  //...
}

module "production" {
  source = "./foobar"

  region   = "TOR"
  hostname = "production"
  //...
}

Under the hood, the module foobar/main.tf would connect to an unknown number of host machines to accomplish this goal, something like:

resource "libvirt_volume" "local-data" {
  host = "${var.region}-rack1-storage.evilcorp.com"
  // ...
}

resource "libvirt_domain" "frontend" {
  host = "${var.region}-rack1-general2.evilcorp.com"
  // ...
}

resource "libvirt_domain" "compute" {
  host = "${var.region}-rack1-gpu2.evilcorp.com"
  // ...
}

Note how doing this with duplicated providers forces an abstraction leak: the IaC engineer working on the backend stuff now has to inform the application programmers that they need 3 providers to be able to call this module. Any changes to metal implementations cause application programmers to need to change their code, or IaC engineers to muck with code that isn't theirs.

I have implemented a full solution to this feature request here: https://github.com/memetb/terraform-provider-libvirt/compare/main...memetb:terraform-provider-libvirt:multi-connection?expand=1
Associated PR #1072

I have not submitted it as a PR because I used a currently outstanding PR as my branch base (I can rebase if there's interest for this to be pushed through).

Implementation Notes

A couple of improvements have been made which are of note:

  • there was an abstraction leak whereby definition modules would make use of locks and therefore need to call the configuration object. This abstraction has been corrected and a lock is obtained via an interface, this allows for...
  • per connection locking to allow for simultaneous deployment across any number of machines
  • for backwards compatibility, the host and uri arguments are both optional:
    • the provider uri argument, when specified, will act as a default URI to connect to
    • a host argument can be passed to any of the resources or data sources: if present, that host uri will be used, if absent the default URI will be used
    • if neither are present an error will be raised
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant