diff --git a/builder/libvirt/network/direct.go b/builder/libvirt/network/direct.go new file mode 100644 index 0000000..4071724 --- /dev/null +++ b/builder/libvirt/network/direct.go @@ -0,0 +1,35 @@ +package network + +import ( + "fmt" + + "github.com/hashicorp/packer-plugin-sdk/template/interpolate" + "libvirt.org/go/libvirtxml" +) + +type DirectNetworkInterface struct { + // For `type = "direct" interfaces, the name of the host direct device which the domain connects to + Dev string `mapstructure:"dev" required:"false"` + Mode string `mapstructure:"mode" required:"false"` +} + +func (ni *DirectNetworkInterface) PrepareConfig(ctx *interpolate.Context) (warnings []string, errs []error) { + errs = []error{} + if ni.Dev == "" { + errs = append(errs, fmt.Errorf("network interfaces with type=direct must specify dev")) + } + if ni.Mode == "" { + errs = append(errs, fmt.Errorf("network interfaces with type=direct must specify mode")) + } + + return +} + +func (ni DirectNetworkInterface) UpdateDomainInterface(domainInterface *libvirtxml.DomainInterface) { + domainInterface.Source = &libvirtxml.DomainInterfaceSource{ + Direct: &libvirtxml.DomainInterfaceSourceDirect{ + Dev: ni.Dev, + Mode: ni.Mode, + }, + } +} diff --git a/builder/libvirt/network/generate.hcl2spec.go b/builder/libvirt/network/generate.hcl2spec.go index 4e88f00..313d6b1 100644 --- a/builder/libvirt/network/generate.hcl2spec.go +++ b/builder/libvirt/network/generate.hcl2spec.go @@ -16,6 +16,8 @@ type FlatNetworkInterface struct { Model *string `mapstructure:"model" required:"false" cty:"model" hcl:"model"` Bridge *string `mapstructure:"bridge" required:"false" cty:"bridge" hcl:"bridge"` Network *string `mapstructure:"network" required:"false" cty:"network" hcl:"network"` + Mode *string `mapstructure:"mode" required:"false" cty:"mode" hcl:"mode"` + Dev *string `mapstructure:"dev" required:"false" cty:"dev" hcl:"dev"` } // FlatMapstructure returns a new FlatNetworkInterface. @@ -36,6 +38,8 @@ func (*FlatNetworkInterface) HCL2Spec() map[string]hcldec.Spec { "model": &hcldec.AttrSpec{Name: "model", Type: cty.String, Required: false}, "bridge": &hcldec.AttrSpec{Name: "bridge", Type: cty.String, Required: false}, "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, + "mode": &hcldec.AttrSpec{Name: "mode", Type: cty.String, Required: false}, + "dev": &hcldec.AttrSpec{Name: "dev", Type: cty.String, Required: false}, } return s } diff --git a/builder/libvirt/network/network.go b/builder/libvirt/network/network.go index 8a4c239..329c191 100644 --- a/builder/libvirt/network/network.go +++ b/builder/libvirt/network/network.go @@ -24,6 +24,7 @@ type NetworkInterface struct { Model string `mapstructure:"model" required:"false"` Bridge BridgeNetworkInterface `mapstructure:",squash"` + Direct DirectNetworkInterface `mapstructure:",squash"` Managed ManagedNetworkInterface `mapstructure:",squash"` } @@ -44,6 +45,8 @@ func (ni *NetworkInterface) PrepareConfig(ctx *interpolate.Context) (warnings [] switch ni.Type { case "managed", "network": w, e = ni.Managed.PrepareConfig(ctx) + case "direct": + w, e = ni.Direct.PrepareConfig(ctx) case "bridge": w, e = ni.Bridge.PrepareConfig(ctx) default: @@ -74,6 +77,8 @@ func (ni NetworkInterface) DomainInterface() *libvirtxml.DomainInterface { } switch ni.Type { + case "direct": + ni.Direct.UpdateDomainInterface(&domainInterface) case "bridge": ni.Bridge.UpdateDomainInterface(&domainInterface) case "managed": diff --git a/libvirt-utils/libvirt_uri.go b/libvirt-utils/libvirt_uri.go index 34b8b3f..0d9c76c 100644 --- a/libvirt-utils/libvirt_uri.go +++ b/libvirt-utils/libvirt_uri.go @@ -52,7 +52,7 @@ func (uri *LibvirtUri) GetExtra(p LibvirtUriExtraParam) (string, bool) { } func (uri *LibvirtUri) Unmarshal(s string) error { - uriRegex := `^(?P[a-z]+)(\+(?P[a-z]+))?://(((?P[a-z_][-a-z0-9_]*\$?)@)?(?P[-_.a-z0-9]+)(:(?P[0-9]+)?)?)?(?P/[-_.a-z0-9]+)?(\?(?P.*))?$` + uriRegex := `^(?P[a-z]+)(\+(?P[a-z]+))?://(((?P[a-z_][-a-z0-9_\.]*\$?)@)?(?P[-_.a-z0-9]+)(:(?P[0-9]+)?)?)?(?P/[-_.a-z0-9]+)?(\?(?P.*))?$` re := regexp.MustCompile(uriRegex) matches := allMatchedRegexpGroups(re, s) diff --git a/libvirt-utils/ssh_dialer.go b/libvirt-utils/ssh_dialer.go index 439aa99..df9eb14 100644 --- a/libvirt-utils/ssh_dialer.go +++ b/libvirt-utils/ssh_dialer.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/packer-plugin-sdk/pathing" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/knownhosts" + "golang.org/x/crypto/ssh/agent" ) type SshDialer struct { @@ -89,31 +90,45 @@ func sshSetAddress(uri LibvirtUri, dialer *SshDialer) error { } func sshDialerSetPrivateKey(uri LibvirtUri, dialer *SshDialer) (err error) { - - keyPath, ok := uri.GetExtra(LibvirtUriParam_Keyfile) - if !ok { - return fmt.Errorf("ssh transport requires %s parameter", LibvirtUriParam_Keyfile) - } - - expandedKeyPath, err := pathing.ExpandUser(keyPath) - + sock, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { return err } - key, err := ioutil.ReadFile(expandedKeyPath) + agent := agent.NewClient(sock) + signers, err := agent.Signers() if err != nil { return err } - parsedKey, err := ssh.ParsePrivateKey(key) + auths := []ssh.AuthMethod{ssh.PublicKeys(signers...)} - if err != nil { - return err - } + dialer.sshConfig.Auth = append(dialer.sshConfig.Auth, auths...) + + keyPath, ok := uri.GetExtra(LibvirtUriParam_Keyfile) + if ok { + expandedKeyPath, err := pathing.ExpandUser(keyPath) - dialer.sshConfig.Auth = append(dialer.sshConfig.Auth, ssh.PublicKeys(parsedKey)) + if err != nil { + return err + } + + key, err := ioutil.ReadFile(expandedKeyPath) + + if err != nil { + return err + } + + parsedKey, err := ssh.ParsePrivateKey(key) + + if err != nil { + return err + } + + dialer.sshConfig.Auth = append(dialer.sshConfig.Auth, ssh.PublicKeys(parsedKey)) + + } return }