Skip to content

Commit

Permalink
add support for proxmox-api-go #339
Browse files Browse the repository at this point in the history
  • Loading branch information
Tinyblargon committed Jun 19, 2024
1 parent b7f985a commit 641d096
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 119 deletions.
1 change: 1 addition & 0 deletions docs/resources/vm_qemu.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ The following arguments are supported in the top level resource block.
| `ciuser` | `str` | | Override the default cloud-init user for provisioning. |
| `cipassword` | `str` | | Override the default cloud-init user's password. Sensitive. |
| `cicustom` | `str` | | Instead specifying ciuser, cipasword, etc... you can specify the path to a custom cloud-init config file here. Grants more flexibility in configuring cloud-init. |
| `ciupgrade` | `bool` | `true` | Whether to upgrade the packages on the guest during provisioning. |
| `searchdomain` | `str` | | Sets default DNS search domain suffix. |
| `nameserver` | `str` | | Sets default DNS server for guest. |
| `sshkeys` | `str` | | Newline delimited list of SSH public keys to add to authorized keys file for the cloud-init user. |
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ go 1.21
toolchain go1.21.0

require (
github.com/Telmate/proxmox-api-go v0.0.0-20240608213934-9d245a204c42
github.com/Telmate/proxmox-api-go v0.0.0-20240616083239-78e131aa830b
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/rs/zerolog v1.33.0
github.com/rs/zerolog v1.32.0
github.com/stretchr/testify v1.9.0

)
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2-proton h1:HKz85FwoXx86kVtTvFke7rgHvq/HoloSUvW5semjFWs=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2-proton/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/Telmate/proxmox-api-go v0.0.0-20240608213934-9d245a204c42 h1:wDo4xTIS+h2hF2m06Gz/Jw0F8fuczh4dZSYgDNEZ7BU=
github.com/Telmate/proxmox-api-go v0.0.0-20240608213934-9d245a204c42/go.mod h1:bscBzOUx0tJAdVGmQvcnoWPg5eI2eJ6anJKV1ueZ1oU=
github.com/Telmate/proxmox-api-go v0.0.0-20240616083239-78e131aa830b h1:uLi3eYDGVbTpowmiibl3elx/7kDONZopypHpmffcPYQ=
github.com/Telmate/proxmox-api-go v0.0.0-20240616083239-78e131aa830b/go.mod h1:O6yNUi0hG9GQLMBgpikSvbnuek1OMweFtbac1sfGuUs=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
Expand Down Expand Up @@ -132,8 +132,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
Expand Down
41 changes: 41 additions & 0 deletions proxmox/Internal/pxapi/dns/nameservers/nameservers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package nameservers

import (
"net/netip"
"strings"
)

func Split(rawNameServers string) *[]netip.Addr {
nameServers := make([]netip.Addr, 0)
if rawNameServers == "" {
return &nameServers
}
nameServerArrays := strings.Split(rawNameServers, " ")
for _, nameServer := range nameServerArrays {
nameServerSubArrays := strings.Split(nameServer, ",")
if len(nameServerSubArrays) > 1 {
tmpNameServers := make([]netip.Addr, len(nameServerSubArrays))
for i, e := range nameServerSubArrays {
tmpNameServers[i], _ = netip.ParseAddr(e)
}
nameServers = append(nameServers, tmpNameServers...)
} else {
tmpNameServer, _ := netip.ParseAddr(nameServer)
nameServers = append(nameServers, tmpNameServer)
}
}
return &nameServers
}

func String(nameServers *[]netip.Addr) string {
if nameServers != nil {
var rawNameServers string
for _, nameServer := range *nameServers {
rawNameServers += " " + nameServer.String()
}
if rawNameServers != "" {
return rawNameServers[1:]
}
}
return ""
}
35 changes: 35 additions & 0 deletions proxmox/Internal/pxapi/guest/sshkeys/sshkeys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package sshkeys

import (
"crypto"
"regexp"
"strings"
)

var regexMultipleSpaces = regexp.MustCompile(`\s+`)

func Split(rawKeys string) *[]crypto.PublicKey {
tmpKeys := strings.Split(rawKeys, "\n")
keys := make([]crypto.PublicKey, len(tmpKeys))
for i, e := range tmpKeys {
keys[i] = crypto.PublicKey(e)
}
return &keys
}

func String(keys *[]crypto.PublicKey) string {
if keys != nil {
var rawKeys string
for _, key := range *keys {
rawKeys += "\n" + key.(string)
}
if rawKeys != "" {
return rawKeys[1:]
}
}
return ""
}

func Trim(rawKeys string) string {
return regexMultipleSpaces.ReplaceAllString(strings.TrimSpace(rawKeys), " ")
}
34 changes: 12 additions & 22 deletions proxmox/heper_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,23 @@ const (
errorGuestAgentNoIPv6Summary string = "Qemu Guest Agent is enabled but no IPv6 address is found"
)

func parseCloudInitInterface(ipConfig string, skipIPv4, skipIPv6 bool) (conn connectionInfo) {
func parseCloudInitInterface(ipConfig pxapi.CloudInitNetworkConfig, ciCustom, skipIPv4, skipIPv6 bool) (conn connectionInfo) {
conn.SkipIPv4 = skipIPv4
conn.SkipIPv6 = skipIPv6
var IPv4Set, IPv6Set bool
for _, e := range strings.Split(ipConfig, ",") {
if len(e) < 4 {
continue
if ipConfig.IPv4 != nil {
if ipConfig.IPv4.Address != nil {
splitCIDR := strings.Split(string(*ipConfig.IPv4.Address), "/")
conn.IPs.IPv4 = splitCIDR[0]
}
if e[:3] == "ip=" {
IPv4Set = true
splitCIDR := strings.Split(e[3:], "/")
if len(splitCIDR) == 2 {
conn.IPs.IPv4 = splitCIDR[0]
}
}
if e[:4] == "ip6=" {
IPv6Set = true
splitCIDR := strings.Split(e[4:], "/")
if len(splitCIDR) == 2 {
conn.IPs.IPv6 = splitCIDR[0]
}
}
}
if !IPv4Set && conn.IPs.IPv4 == "" {
} else if !ciCustom {
conn.SkipIPv4 = true
}
if !IPv6Set && conn.IPs.IPv6 == "" {
if ipConfig.IPv6 != nil {
if ipConfig.IPv6.Address != nil {
splitCIDR := strings.Split(string(*ipConfig.IPv6.Address), "/")
conn.IPs.IPv6 = splitCIDR[0]
}
} else if !ciCustom {
conn.SkipIPv6 = true
}
return
Expand Down
103 changes: 91 additions & 12 deletions proxmox/heper_qemu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ func Test_HasRequiredIP(t *testing.T) {

func Test_ParseCloudInitInterface(t *testing.T) {
type testInput struct {
ci string
ci pxapi.CloudInitNetworkConfig
ciCustom bool
skipIPv4 bool
skipIPv6 bool
}
Expand All @@ -161,60 +162,138 @@ func Test_ParseCloudInitInterface(t *testing.T) {
output connectionInfo
}{
{name: `IPv4=DHCP`,
input: testInput{ci: "ip=dhcp"},
output: connectionInfo{SkipIPv6: true}},
input: testInput{ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
DHCP: true}}},
output: connectionInfo{
SkipIPv6: true}},
{name: `IPv4=DHCP ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
DHCP: true}},
ciCustom: true}},
{name: `IPv4=DHCP SkipIPv4`,
input: testInput{
ci: "ip=dhcp",
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
DHCP: true}},
skipIPv4: true},
output: connectionInfo{
SkipIPv4: true,
SkipIPv6: true}},
{name: `IPv4=DHCP SkipIPv4 ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
DHCP: true}},
ciCustom: true,
skipIPv4: true},
output: connectionInfo{SkipIPv4: true}},
{name: `IPv4=Static`,
input: testInput{ci: "ip=192.168.1.1/24"},
input: testInput{ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))}}},
output: connectionInfo{IPs: primaryIPs{
IPv4: "192.168.1.1"},
SkipIPv6: true}},
{name: `IPv4=Static ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))}},
ciCustom: true},
output: connectionInfo{IPs: primaryIPs{IPv4: "192.168.1.1"}}},
{name: `IPv4=Static IPv6=Static`,
input: testInput{ci: "ip=192.168.1.1/24,ip6=2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"},
input: testInput{ci: pxapi.CloudInitNetworkConfig{
IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))},
IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}}},
output: connectionInfo{IPs: primaryIPs{
IPv4: "192.168.1.1",
IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"}}},
{name: `IPv4=Static IPv6=Static ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{
IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))},
IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}},
ciCustom: true},
output: connectionInfo{IPs: primaryIPs{
IPv4: "192.168.1.1",
IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"}}},
{name: `IPv4=Static SkipIPv4`,
input: testInput{
ci: "ip=192.168.1.1/24",
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))}},
skipIPv4: true},
output: connectionInfo{IPs: primaryIPs{
IPv4: "192.168.1.1"},
SkipIPv4: true,
SkipIPv6: true}},
{name: `IPv4=Static SkipIPv4 ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv4: &pxapi.CloudInitIPv4Config{
Address: pointer(pxapi.IPv4CIDR("192.168.1.1/24"))}},
ciCustom: true,
skipIPv4: true},
output: connectionInfo{IPs: primaryIPs{
IPv4: "192.168.1.1"},
SkipIPv4: true}},
{name: `IPv6=DHCP`,
input: testInput{ci: "ip6=dhcp"},
input: testInput{ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
DHCP: true}}},
output: connectionInfo{SkipIPv4: true}},
{name: `IPv6=DHCP ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
DHCP: true}},
ciCustom: true}},
{name: `IPv6=DHCP SkipIPv6`,
input: testInput{
ci: "ip6=dhcp",
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
DHCP: true}},
skipIPv6: true},
output: connectionInfo{
SkipIPv4: true,
SkipIPv6: true}},
{name: `IPv6=DHCP SkipIPv6 ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
DHCP: true}},
ciCustom: true,
skipIPv6: true},
output: connectionInfo{SkipIPv6: true}},
{name: `IPv6=Static`,
input: testInput{ci: "ip6=2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"},
input: testInput{ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}}},
output: connectionInfo{IPs: primaryIPs{
IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
SkipIPv4: true}},
{name: `IPv6=Static ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}},
ciCustom: true},
output: connectionInfo{IPs: primaryIPs{IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"}}},
{name: `IPv6=Static SkipIPv6`,
input: testInput{
ci: "ip6=2001:0db8:85a3:0000:0000:8a2e:0370:7334/64",
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}},
skipIPv6: true},
output: connectionInfo{IPs: primaryIPs{
IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
SkipIPv4: true,
SkipIPv6: true}},
{name: `IPv6=Static SkipIPv6 ciCustom`,
input: testInput{
ci: pxapi.CloudInitNetworkConfig{IPv6: &pxapi.CloudInitIPv6Config{
Address: pointer(pxapi.IPv6CIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"))}},
ciCustom: true,
skipIPv6: true},
output: connectionInfo{IPs: primaryIPs{
IPv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
SkipIPv6: true}},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require.Equal(t, test.output, parseCloudInitInterface(test.input.ci, test.input.skipIPv4, test.input.skipIPv6))
require.Equal(t, test.output, parseCloudInitInterface(test.input.ci, test.input.ciCustom, test.input.skipIPv4, test.input.skipIPv6))
})
}
}
Expand Down
Loading

0 comments on commit 641d096

Please sign in to comment.