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

version 0.7.4 breaks qemu+ssh (libvirt-sock) connection #1040

Closed
n-able-consulting opened this issue Oct 17, 2023 · 7 comments · Fixed by #1044
Closed

version 0.7.4 breaks qemu+ssh (libvirt-sock) connection #1040

n-able-consulting opened this issue Oct 17, 2023 · 7 comments · Fixed by #1044

Comments

@n-able-consulting
Copy link

n-able-consulting commented Oct 17, 2023

System Information

amd64

Linux distribution

Ubuntu22.04

Terraform version

v1.6.1

Provider and libvirt versions

0.7.4


Description of Issue/Question

I use the plugin to provision vm's on rack within my network.
I always implement an install with the latest Terraform and plugin versions.
With version 0.7.4. I get the following error when executing my code:
Error: failed to connect: dial unix /var/run/libvirt/libvirt-sock: connect: permission denied

│ with provider["registry.terraform.io/dmacvicar/libvirt"],
│ on connection.tf line 14, in provider "libvirt":
│ 14: provider "libvirt" {

Falling back to version 0.7.1 (since it is the latest version that is useable): it works again.

Setup

my connection.tf not working

terraform {
 required_version = ">= 1.6.1"
  required_providers {
    libvirt = {
      version  = "0.7.4"
      source  = "dmacvicar/libvirt"
    }
  }
}


# instance the provider
provider "libvirt" {
  uri = "qemu+ssh://user@xxx.xxx.hosts/system?keyfile=/home/xxx/.ssh/xxx&sshauth=privkey"
}

my connection.tf working

terraform {
 required_version = ">= 1.6.1"
  required_providers {
    libvirt = {
      version  = "0.7.1"
      source  = "dmacvicar/libvirt"
    }
  }
}


# instance the provider
provider "libvirt" {
  uri = "qemu+ssh://user@xxx.xxx.hosts/system?keyfile=/home/xxx/.ssh/xxx&sshauth=privkey"
}
@niklas-truesec
Copy link

This also seems to break usage of user session URIs

provider "libvirt" {
uri = "qemu:///session?socket=/run/user/1000/libvirt/virtqemud-sock"
}

@nerzhul
Copy link

nerzhul commented Oct 20, 2023

same issue with bhyve+ssh://

@X-Cli
Copy link
Contributor

X-Cli commented Nov 3, 2023

The issue is that the connectionURI is modified by the call to RemoteName() done during the call to Dial by go-libvirt. As it seems, the copy of the URI is shallow and thus, calling Dial during a ConnectToURI on the RemoteName() causes the Dial call to contact the RemoteName instead of the configured URI.

I managed to fix the bug by replacing the copy with the following initialization:

	newURI := url.URL{
		Scheme: u.driver(),
		Path:   u.Path,
	}

The issue was not present before because the dial was done prior to passing the connection to go-libvirt and prior to the call of the RemoteName() function.

X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and
this corrupted to original URI that is used during
the Dial() call made by the go-libvirt library.

The issue always existed but did not manifest when
libvirt.New(conn) was used because the connection was
established before the call to RemoteName. The
problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing
is now made during the call to ConnectToURI, which
receives as paramater the result of the call to
RemoteName.
@michaelbeaumont
Copy link
Collaborator

@X-Cli Good catch. It feels to me like the real fix is not having a pointer to a URL inside ConnectionURI, which is what makes the shallow copy useless.

type ConnectionURI struct {
	url.URL
}

Can you try that out/open a PR?

@elasmo
Copy link

elasmo commented Nov 3, 2023

Could be related to what @X-Cli is mentioning. I'm having issues connecting using qemu+tls.

main.tf:

terraform {
  required_providers {
    libvirt = {
      source  = "dmacvicar/libvirt"
      version = "0.7.4"
    }
  }
}

provider "libvirt" {
  uri = "qemu+tls://libvirt.example.tld/system"
}

resource "libvirt_domain" "test" {
  name = "Test"
}
$ TF_LOG=DEBUG terraform plan
2023-11-03T12:37:30.115+0100 [INFO]  Terraform version: 1.6.2
2023-11-03T12:37:30.115+0100 [DEBUG] using github.com/hashicorp/go-tfe v1.36.0
2023-11-03T12:37:30.115+0100 [DEBUG] using github.com/hashicorp/hcl/v2 v2.19.1
2023-11-03T12:37:30.115+0100 [DEBUG] using github.com/hashicorp/terraform-svchost v0.1.1
2023-11-03T12:37:30.115+0100 [DEBUG] using github.com/zclconf/go-cty v1.14.1
2023-11-03T12:37:30.115+0100 [INFO]  Go runtime version: go1.21.1
2023-11-03T12:37:30.115+0100 [INFO]  CLI args: []string{"terraform", "plan"}
2023-11-03T12:37:30.115+0100 [DEBUG] Attempting to open CLI config file: /home/user/.terraformrc
2023-11-03T12:37:30.115+0100 [DEBUG] File doesn't exist, but doesn't need to. Ignoring.
2023-11-03T12:37:30.116+0100 [DEBUG] ignoring non-existing provider search directory terraform.d/plugins
2023-11-03T12:37:30.116+0100 [DEBUG] ignoring non-existing provider search directory /home/user/.terraform.d/plugins
2023-11-03T12:37:30.116+0100 [DEBUG] ignoring non-existing provider search directory /home/user/.local/share/terraform/plugins
2023-11-03T12:37:30.116+0100 [DEBUG] ignoring non-existing provider search directory /usr/local/share/terraform/plugins
2023-11-03T12:37:30.116+0100 [DEBUG] ignoring non-existing provider search directory /usr/share/terraform/plugins
2023-11-03T12:37:30.116+0100 [INFO]  CLI command args: []string{"plan"}
2023-11-03T12:37:30.117+0100 [DEBUG] New state was assigned lineage "180c2c10-411f-61f4-2b91-0112ae838318"
2023-11-03T12:37:30.128+0100 [DEBUG] checking for provisioner in "."
2023-11-03T12:37:30.129+0100 [DEBUG] checking for provisioner in "/usr/bin"
2023-11-03T12:37:30.130+0100 [INFO]  backend/local: starting Plan operation
2023-11-03T12:37:30.131+0100 [DEBUG] created provider logger: level=debug
2023-11-03T12:37:30.131+0100 [INFO]  provider: configuring client automatic mTLS
2023-11-03T12:37:30.136+0100 [DEBUG] provider: starting plugin: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 args=[".terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4"]
2023-11-03T12:37:30.136+0100 [DEBUG] provider: plugin started: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18656
2023-11-03T12:37:30.136+0100 [DEBUG] provider: waiting for RPC address: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4
2023-11-03T12:37:30.142+0100 [INFO]  provider.terraform-provider-libvirt_v0.7.4: configuring server automatic mTLS: timestamp="2023-11-03T12:37:30.142+0100"
2023-11-03T12:37:30.155+0100 [DEBUG] provider: using plugin: version=5
2023-11-03T12:37:30.155+0100 [DEBUG] provider.terraform-provider-libvirt_v0.7.4: plugin address: address=/tmp/plugin2606746144 network=unix timestamp="2023-11-03T12:37:30.155+0100"
2023-11-03T12:37:30.175+0100 [DEBUG] provider.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = error reading from server: EOF"
2023-11-03T12:37:30.179+0100 [DEBUG] provider: plugin process exited: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18656
2023-11-03T12:37:30.179+0100 [DEBUG] provider: plugin exited
2023-11-03T12:37:30.179+0100 [DEBUG] Building and walking validate graph
2023-11-03T12:37:30.180+0100 [DEBUG] ProviderTransformer: "libvirt_domain.test" (*terraform.NodeValidatableResource) needs provider["registry.terraform.io/dmacvicar/libvirt"]
2023-11-03T12:37:30.180+0100 [DEBUG] ReferenceTransformer: "libvirt_domain.test" references: []
2023-11-03T12:37:30.180+0100 [DEBUG] ReferenceTransformer: "provider[\"registry.terraform.io/dmacvicar/libvirt\"]" references: []
2023-11-03T12:37:30.181+0100 [DEBUG] Starting graph walk: walkValidate
2023-11-03T12:37:30.181+0100 [DEBUG] created provider logger: level=debug
2023-11-03T12:37:30.181+0100 [INFO]  provider: configuring client automatic mTLS
2023-11-03T12:37:30.185+0100 [DEBUG] provider: starting plugin: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 args=[".terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4"]
2023-11-03T12:37:30.186+0100 [DEBUG] provider: plugin started: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18670
2023-11-03T12:37:30.186+0100 [DEBUG] provider: waiting for RPC address: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4
2023-11-03T12:37:30.191+0100 [INFO]  provider.terraform-provider-libvirt_v0.7.4: configuring server automatic mTLS: timestamp="2023-11-03T12:37:30.191+0100"
2023-11-03T12:37:30.201+0100 [DEBUG] provider: using plugin: version=5
2023-11-03T12:37:30.201+0100 [DEBUG] provider.terraform-provider-libvirt_v0.7.4: plugin address: address=/tmp/plugin181566249 network=unix timestamp="2023-11-03T12:37:30.200+0100"
2023-11-03T12:37:30.217+0100 [DEBUG] provider.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = error reading from server: EOF"
2023-11-03T12:37:30.217+0100 [DEBUG] provider: plugin process exited: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18670
2023-11-03T12:37:30.217+0100 [DEBUG] provider: plugin exited
2023-11-03T12:37:30.218+0100 [INFO]  backend/local: plan calling Plan
2023-11-03T12:37:30.218+0100 [DEBUG] Building and walking plan graph for NormalMode
2023-11-03T12:37:30.218+0100 [DEBUG] ProviderTransformer: "libvirt_domain.test (expand)" (*terraform.nodeExpandPlannableResource) needs provider["registry.terraform.io/dmacvicar/libvirt"]
2023-11-03T12:37:30.218+0100 [DEBUG] ReferenceTransformer: "libvirt_domain.test (expand)" references: []
2023-11-03T12:37:30.218+0100 [DEBUG] ReferenceTransformer: "provider[\"registry.terraform.io/dmacvicar/libvirt\"]" references: []
2023-11-03T12:37:30.218+0100 [DEBUG] Starting graph walk: walkPlan
2023-11-03T12:37:30.218+0100 [DEBUG] created provider logger: level=debug
2023-11-03T12:37:30.218+0100 [INFO]  provider: configuring client automatic mTLS
2023-11-03T12:37:30.221+0100 [DEBUG] provider: starting plugin: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 args=[".terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4"]
2023-11-03T12:37:30.222+0100 [DEBUG] provider: plugin started: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18684
2023-11-03T12:37:30.222+0100 [DEBUG] provider: waiting for RPC address: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4
2023-11-03T12:37:30.226+0100 [INFO]  provider.terraform-provider-libvirt_v0.7.4: configuring server automatic mTLS: timestamp="2023-11-03T12:37:30.226+0100"
2023-11-03T12:37:30.234+0100 [DEBUG] provider: using plugin: version=5
2023-11-03T12:37:30.234+0100 [DEBUG] provider.terraform-provider-libvirt_v0.7.4: plugin address: address=/tmp/plugin1548367601 network=unix timestamp="2023-11-03T12:37:30.234+0100"
2023-11-03T12:37:30.253+0100 [INFO]  provider.terraform-provider-libvirt_v0.7.4: 2023/11/03 12:37:30 [DEBUG] Configuring provider for 'qemu+tls://libvirt.example.tld/system': &{map[uri:0xc0003ea500] <nil> <nil> 0xc00034c680 map[] <nil> {{<nil>} <nil>} 0xc000120160 0xc000132450 0xc000291ad0 false {1 {0 0}} false false}: timestamp="2023-11-03T12:37:30.252+0100"
2023-11-03T12:37:30.253+0100 [ERROR] provider.terraform-provider-libvirt_v0.7.4: Response contains error diagnostic: @caller=github.com/hashicorp/terraform-plugin-go@v0.14.2/tfprotov5/internal/diag/diagnostics.go:55 diagnostic_detail="" diagnostic_severity=ERROR tf_proto_version=5.3 tf_req_id=c3645f64-4cbb-70af-f2d3-8256215c7cc2 @module=sdk.proto diagnostic_summary="failed to connect: dial unix /var/run/libvirt/libvirt-sock: connect: no such file or directory" tf_provider_addr=provider tf_rpc=Configure timestamp="2023-11-03T12:37:30.253+0100"
2023-11-03T12:37:30.253+0100 [ERROR] vertex "provider[\"registry.terraform.io/dmacvicar/libvirt\"]" error: failed to connect: dial unix /var/run/libvirt/libvirt-sock: connect: no such file or directory
2023-11-03T12:37:30.253+0100 [INFO]  backend/local: plan operation completed

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: failed to connect: dial unix /var/run/libvirt/libvirt-sock: connect: no such file or directory
│ 
│   with provider["registry.terraform.io/dmacvicar/libvirt"],
│   on main.tf line 10, in provider "libvirt":
│   10: provider "libvirt" {
│ 
╵
2023-11-03T12:37:30.254+0100 [DEBUG] provider.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = error reading from server: EOF"
2023-11-03T12:37:30.255+0100 [DEBUG] provider: plugin process exited: path=.terraform/providers/registry.terraform.io/dmacvicar/libvirt/0.7.4/linux_amd64/terraform-provider-libvirt_v0.7.4 pid=18684
2023-11-03T12:37:30.255+0100 [DEBUG] provider: plugin exited

X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and this corrupted to
original URI that is used during the Dial() call made by the go-libvirt
library.

The issue always existed but did not manifest when libvirt.New(conn) was
used because the connection was established before the call to
RemoteName. The problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing is now made during
the call to ConnectToURI, which receives as paramater the result of the
call to RemoteName.
@X-Cli
Copy link
Contributor

X-Cli commented Nov 3, 2023

@X-Cli Good catch. It feels to me like the real fix is not having a pointer to a URL inside ConnectionURI, which is what makes the shallow copy useless.

type ConnectionURI struct {
	url.URL
}

As far as I know Go, this syntax is not exactly a pointer; it is a syntactic sugar for ConnectionURI to have the same attributes, current and future, as a url.URL. The type is only used as a proxy for url.URL augmented with the Dialer implementation, and a few private functions. However, you are correct that if RemoteName receiver was not a pointer, the ConnectionURI instance would not have been modified either.

I have modified my code to do both, just in case :)

X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and this corrupted to
original URI that is used during the Dial() call made by the go-libvirt
library.

The issue always existed but did not manifest when libvirt.New(conn) was
used because the connection was established before the call to
RemoteName. The problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing is now made during
the call to ConnectToURI, which receives as paramater the result of the
call to RemoteName.
X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and this corrupted the
original URI that is used during the Dial() call made by the go-libvirt
library.

The issue always existed but did not manifest when libvirt.New(conn) was
used because the connection was established before the call to
RemoteName. The problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing is now made during
the call to ConnectToURI, which receives as paramater the result of the
call to RemoteName.
@michaelbeaumont
Copy link
Collaborator

michaelbeaumont commented Nov 3, 2023

As far as I know Go, this syntax is not exactly a pointer;

In fact that's what *url.URL ensures. There's implicitly a URL: *url.URL field, so that on a shallow copy of ConnectionURI, the pointer itself is copied, not the value pointed to by the pointer. And so the subsequent statements like newURI.User = nil modify the original value u.URL.User via the newURI.URL *url.URL via the pointer receiver u *ConnectionURI when we call u.RemoteName().

The change from:

type ConnectionURI struct {
	*url.URL
}

to

type ConnectionURI struct {
	url.URL
}

would make it so that ConnectionURI wraps a value, not a pointer. Preventing unintentional mutation of the URL contained in ConnectionURI. It seems to me very unlikely that a shallow copy of a ConnectionURI is meant to preserve mutability of the contained URL, though I can't be sure without a deeper look at the code.

So the pointer receiver change is actually unnecessary, since the shallow copy of ConnectionURI still points to the same URL.

X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and this corrupted the
original URI that is used during the Dial() call made by the go-libvirt
library.

The issue always existed but did not manifest when libvirt.New(conn) was
used because the connection was established before the call to
RemoteName. The problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing is now made during
the call to ConnectToURI, which receives as paramater the result of the
call to RemoteName.
X-Cli pushed a commit to X-Cli/terraform-provider-libvirt that referenced this issue Nov 3, 2023
Fixes dmacvicar#1040

The copy performed in RemoteName was shallow and this corrupted the
original URI that is used during the Dial() call made by the go-libvirt
library.

The issue always existed but did not manifest when libvirt.New(conn) was
used because the connection was established before the call to
RemoteName. The problem manifested when the switch to
libvirt.NewWithDialer was made, because the dialing is now made during
the call to ConnectToURI, which receives as paramater the result of the
call to RemoteName.
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

Successfully merging a pull request may close this issue.

6 participants