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

allow specifying of target host machine on every individual resource/data source #1072

Draft
wants to merge 65 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ba090fc
bump ssh_config to stable version which contains GetAll call
Dec 20, 2023
19893fc
refactor dialSSH and break out dialHost as support function
Dec 20, 2023
94ae671
move authentication parsing to per host part of loop
Dec 20, 2023
76ed8d0
implement per Host identity file lookup
Dec 20, 2023
7dacf0b
fix tilde (~) based home directory notation for convenience
Dec 20, 2023
7273b7d
updated go.sum
Dec 20, 2023
4abb01a
cleanup log outputs
Dec 21, 2023
f190d80
remove unnecessary local variable
Dec 21, 2023
401c36c
Add none option to graphics
flx5 Dec 30, 2023
329a202
make use of net package URI building to support correct ipv6
Jan 16, 2024
c1e4fbf
correctly use host:port format when dialing bastion host
Jan 28, 2024
100f82b
put quotes around target in case it is empty
Jan 28, 2024
e203600
if the hostname override isn't present, simply use target name
Jan 28, 2024
d47102d
add log output for port override
Jan 28, 2024
35d6a04
add a node info query data source
Feb 21, 2024
5f61a7b
add a preliminary test
Feb 21, 2024
2a12896
add readme entry for modification
Feb 22, 2024
82b491d
update provider and config structure
Feb 22, 2024
c20d2db
rename config to client to match implemented classes
Feb 22, 2024
781ad9e
remove locking from volume.go as this is an abstraction leak
Feb 22, 2024
673e954
update cloudinit implementations to match new architecture
Feb 22, 2024
fdd1a32
update all networking implementations (same comments as 673e954b)
Feb 22, 2024
12199ef
add per connection mutex' for speed up and abstraction leak fix
Feb 22, 2024
c8facd8
make use of per-connection locking mechanism
Feb 22, 2024
1516454
add default host key algorithm
Feb 22, 2024
7caaf18
move port configuration earlier so that hostkey callback works right
Feb 22, 2024
ad51d68
cleanup log output, add error handling for dial host
Feb 22, 2024
6754108
add support for sshconfig based known hosts file behaviour
Feb 22, 2024
60cf3f1
integrate HostKeyAlgorithms ssh_config option
Feb 22, 2024
060987d
move dial host impl so that bastion hosts have same features
Feb 22, 2024
31af282
add comments
Feb 22, 2024
3680059
use a more modern default host key
Feb 22, 2024
615b189
update auth method parse to allow for multiple private ssh keys
Feb 22, 2024
6407d2b
add readme entry for modification
Feb 22, 2024
18fe843
update provider and config structure
Feb 22, 2024
9dff3e0
rename config to client to match implemented classes
Feb 22, 2024
2291b1b
remove locking from volume.go as this is an abstraction leak
Feb 22, 2024
cc90152
update cloudinit implementations to match new architecture
Feb 22, 2024
da5cda1
update all networking implementations (same comments as 673e954b)
Feb 22, 2024
88946d3
Merge branch 'ssh-config-parameters' into production
Feb 22, 2024
0dff8f9
Merge branch 'multi-connection-private' into production
Feb 22, 2024
9306274
update error string to match resource arguments
Feb 22, 2024
171ce55
update error string to match resource arguments
Feb 22, 2024
580e778
correctly deal with default uri/host args
Feb 22, 2024
776958c
add trace log to output default URI
Feb 22, 2024
b2d024b
correctly deal with default uri/host args
Feb 22, 2024
6228a00
correctly deal with default uri/host args (same as 580e7785)
Feb 22, 2024
082f086
use a list of hostKeyAlgorithms instead of just one default
Feb 22, 2024
a88abaf
Merge branch 'ssh-config-parameters' into production
Feb 22, 2024
dec8f23
use a list of hostKeyAlgorithms instead of just one default
Feb 22, 2024
3053906
Merge branch 'ssh-config-parameters' into production
Feb 22, 2024
816d963
Merge branch 'main' into multi-connection
Feb 23, 2024
892b1b6
add multi-host code for missing data sources
Feb 23, 2024
b503b73
remove incorrectly included file from feature branch
Feb 23, 2024
46215ff
update error messages to match source location
Feb 23, 2024
a6fd68c
Merge branch 'main' into production
Feb 23, 2024
1768b27
remove node info data source impl from #1059
Feb 23, 2024
efd8262
rename node-info impl to match other data sources
Feb 23, 2024
57b3c57
Merge branch 'dmacvicar:main' into production
memetb Feb 23, 2024
e0c49a9
Merge branch 'production' of github.com:memetb/terraform-provider-lib…
Feb 23, 2024
112116a
Merge pull request #6 from memetb/graphics-none-option
memetb Feb 23, 2024
93188e4
Merge branch 'production' into multi-connection
memetb Feb 23, 2024
c42a1fc
Revert "Add none option to graphics"
Feb 23, 2024
0db9931
remove duplicated file
Feb 23, 2024
4671752
remove duplicated data source entry
Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ The binary will be called `terraform-provider-libvirt`.

You can target different libvirt hosts instantiating the [provider multiple times](https://www.terraform.io/docs/configuration/providers.html#multiple-provider-instances). [Example](examples/v0.12/multiple).

Alternatively, you can specify the `host` argument on any of the data or resources. This can be useful if a module implements internal resource management that is distributed within a hosting environment (e.g. multiple servers in close proximity to each other)

### Using qemu-agent

From its documentation, [qemu-agent](https://wiki.libvirt.org/page/Qemu_guest_agent):
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/google/uuid v1.3.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/hooklift/iso9660 v1.0.0
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351
github.com/kevinburke/ssh_config v1.2.0
github.com/mattn/goveralls v0.0.11
github.com/stretchr/testify v1.8.1
golang.org/x/crypto v0.17.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
Expand Down
128 changes: 128 additions & 0 deletions libvirt/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package libvirt

import (
"fmt"
"log"
"sync"
"errors"
libvirt "github.com/digitalocean/go-libvirt"
"github.com/dmacvicar/terraform-provider-libvirt/libvirt/helper/mutexkv"
uri "github.com/dmacvicar/terraform-provider-libvirt/libvirt/uri"
)

type Connection struct {
connection *libvirt.Libvirt
poolMutexKV *mutexkv.MutexKV

// define only one network at a time
// https://gitlab.com/libvirt/libvirt/-/issues/78
// note: this issue has been resolved in 2021 https://gitlab.com/libvirt/libvirt/-/commit/ea0cfa11
networkMutex sync.Mutex
}

// Client libvirt.
type Client struct {
defaultURI string
connections map[string]*Connection
}

// obtain a connection for this provider, if target is empty, use the default provider connection
func (c *Client) Connection(target *string) (*libvirt.Libvirt , error) {

URI := c.defaultURI
if target != nil && *target != "" {
URI = *target
}

if URI == "" {
return nil, errors.New("either the provider-wide default `uri` or the resource block `host` must be specified")
}

log.Printf("[DEBUG] Configuring connection for target host '%s'", URI)

if conn, ok := c.connections[URI] ; ok {
log.Printf("[DEBUG] Found existing connection for target host: '%s'", URI)
return conn.connection, nil
}

u, err := uri.Parse(URI)
if err != nil {
return nil, err
}

l := libvirt.NewWithDialer(u)

if err := l.ConnectToURI(libvirt.ConnectURI(u.RemoteName())); err != nil {
return nil, fmt.Errorf("failed to connect: %w", err)
}

v, err := l.ConnectGetLibVersion()
if err != nil {
return nil, fmt.Errorf("failed to retrieve libvirt version: %w", err)
}
log.Printf("[INFO] libvirt client libvirt version: %v\n", v)

conn := &Connection {
connection: l,
poolMutexKV: mutexkv.NewMutexKV(),
}
c.connections[URI] = conn
return conn.connection, nil
}

// obtain a Lock for this client, don't create if not found since the network connection must exist anyways to get this far
func (c *Client) GetLock(target *string) (*mutexkv.MutexKV) {

URI := c.defaultURI
if target != nil && *target != "" {
URI = *target
}

if URI == "" {
// if we get here, somehow the calling code was able top get a live connection but the
// connection string doesn't exist. This breaks a code invariant and is indicative of a bug.
log.Printf("[WARN] unable to find mutex for '%v' - this is not expected behaviour", target)
return nil
}

if conn, ok := c.connections[URI] ; ok {
return conn.poolMutexKV
}

return nil
}

// obtain a Lock for this client, don't create if not found since the network connection must exist anyways to get this far
func (c *Client) GetMutex(target *string) (*sync.Mutex) {

URI := c.defaultURI
if target != nil && *target != "" {
URI = *target
}

if URI == "" {
// if we get here, somehow the calling code was able top get a live connection but the
// connection string doesn't exist. This breaks a code invariant and is indicative of a bug.
log.Printf("[WARN] unable to find mutex for '%v' - this is not expected behaviour", target)
return nil
}

if conn, ok := c.connections[URI] ; ok {
return &conn.networkMutex
}

return nil
}

// Close all connections associated with this provider instance
func (c *Client) Close() {

for uri, c := range c.connections {
log.Printf("[DEBUG] cleaning up connection for URI: %s", uri)
// TODO: Confirm appropriate IsAlive() validation
err := c.connection.ConnectClose()
if err != nil {
log.Printf("[ERROR] cannot close libvirt connection: %v", err)
}
}
}
9 changes: 1 addition & 8 deletions libvirt/cloudinit_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,12 @@ func removeTmpIsoDirectory(iso string) {

}

func (ci *defCloudInit) UploadIso(client *Client, iso string) (string, error) {
virConn := client.libvirt
if virConn == nil {
return "", fmt.Errorf(LibVirtConIsNil)
}

func (ci *defCloudInit) UploadIso(virConn *libvirt.Libvirt, iso string) (string, error) {
pool, err := virConn.StoragePoolLookupByName(ci.PoolName)
if err != nil {
return "", fmt.Errorf("can't find storage pool '%s'", ci.PoolName)
}

client.poolMutexKV.Lock(ci.PoolName)
defer client.poolMutexKV.Unlock(ci.PoolName)

// Refresh the pool of the volume so that libvirt knows it is
// not longer in use.
Expand Down
52 changes: 0 additions & 52 deletions libvirt/config.go

This file was deleted.

9 changes: 1 addition & 8 deletions libvirt/coreos_ignition_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,12 @@ func newIgnitionDef() defIgnition {
// Create a ISO file based on the contents of the CloudInit instance and
// uploads it to the libVirt pool
// Returns a string holding terraform's internal ID of this resource.
func (ign *defIgnition) CreateAndUpload(client *Client) (string, error) {
virConn := client.libvirt
if virConn == nil {
return "", fmt.Errorf(LibVirtConIsNil)
}

func (ign *defIgnition) CreateAndUpload(virConn *libvirt.Libvirt) (string, error) {
pool, err := virConn.StoragePoolLookupByName(ign.PoolName)
if err != nil {
return "", fmt.Errorf("can't find storage pool '%s'", ign.PoolName)
}

client.poolMutexKV.Lock(ign.PoolName)
defer client.poolMutexKV.Unlock(ign.PoolName)

// Refresh the pool of the volume so that libvirt knows it is
// not longer in use.
Expand Down
10 changes: 8 additions & 2 deletions libvirt/data_source_libvirt_node_device_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ func datasourceLibvirtNodeDeviceInfo() *schema.Resource {
return &schema.Resource{
Read: resourceLibvirtNodeDeviceInfoRead,
Schema: map[string]*schema.Schema{
"host" : {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -464,9 +469,10 @@ func datasourceLibvirtNodeDeviceInfo() *schema.Resource {
func resourceLibvirtNodeDeviceInfoRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Read data source libvirt_nodedevices")

virConn := meta.(*Client).libvirt
uri := d.Get("host").(string)
virConn, err := meta.(*Client).Connection(&uri)
if virConn == nil {
return fmt.Errorf(LibVirtConIsNil)
return fmt.Errorf("unable to connect for node deviceinfo read: %v", err)
}

var deviceName string
Expand Down
10 changes: 8 additions & 2 deletions libvirt/data_source_libvirt_node_devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ func datasourceLibvirtNodeDevices() *schema.Resource {
return &schema.Resource{
Read: resourceLibvirtNodeDevicesRead,
Schema: map[string]*schema.Schema{
"host" : {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"capability": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -43,9 +48,10 @@ func datasourceLibvirtNodeDevices() *schema.Resource {
func resourceLibvirtNodeDevicesRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Read data source libvirt_nodedevices")

virConn := meta.(*Client).libvirt
uri := d.Get("host").(string)
virConn, err := meta.(*Client).Connection(&uri)
if virConn == nil {
return fmt.Errorf(LibVirtConIsNil)
return fmt.Errorf("unable to connect for node devices read: %v", err)
}

var cap libvirt.OptString
Expand Down
Loading