Skip to content

Commit 59736fb

Browse files
authored
Merge branch 'bpg:main' into remove-network-device
2 parents 2c69512 + a32988a commit 59736fb

File tree

5 files changed

+298
-12
lines changed

5 files changed

+298
-12
lines changed

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.25.3@sha256:7d73c4c57127279b23f3f70cbb368bf0fe08f7ab32af5daf5764173d25e78b74
1+
FROM golang:1.25.3@sha256:8c945d3e25320e771326dafc6fb72ecae5f87b0f29328cbbd87c4dff506c9135
22

33
ARG GOLANGCI_LINT_VERSION=2.5.0 # renovate: depName=golangci/golangci-lint datasource=github-releases
44

docs/resources/virtual_environment_container.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ output "ubuntu_container_public_key" {
144144
- `initialization` - (Optional) The initialization configuration.
145145
- `dns` - (Optional) The DNS configuration.
146146
- `domain` - (Optional) The DNS search domain.
147-
- `server` - (Optional) The DNS server. The `server` attribute is
148-
deprecated and will be removed in a future release. Please use
147+
- `server` - (Optional) The DNS server.
148+
The `server` attribute is deprecated and will be removed in a future release. Please use
149149
the `servers` attribute instead.
150150
- `servers` - (Optional) The list of DNS servers.
151151
- `hostname` - (Optional) The hostname.

fwprovider/test/resource_container_test.go

Lines changed: 222 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ func TestAccResourceContainer(t *testing.T) {
3838
accTestContainerIDClone := 100000 + rand.Intn(99999)
3939

4040
te.AddTemplateVars(map[string]interface{}{
41-
"ImageFileName": imageFileName,
42-
"TestContainerID": accTestContainerID,
43-
"TestContainerIDClone": accTestContainerIDClone,
41+
"ImageFileName": imageFileName,
42+
"TestContainerID": accTestContainerID,
43+
"TestContainerIDClone": accTestContainerIDClone,
4444
})
4545

4646
err := te.NodeStorageClient().DownloadFileByURL(context.Background(), &storage.DownloadURLPostRequestBody{
@@ -512,6 +512,225 @@ func TestAccResourceContainer(t *testing.T) {
512512
),
513513
},
514514
}},
515+
{"empty dns block on update", []resource.TestStep{
516+
{
517+
Config: te.RenderConfig(`
518+
resource "proxmox_virtual_environment_container" "test_container" {
519+
node_name = "{{.NodeName}}"
520+
unprivileged = true
521+
disk {
522+
datastore_id = "local-lvm"
523+
size = 4
524+
}
525+
initialization {
526+
hostname = "test-dns-issue"
527+
ip_config {
528+
ipv4 {
529+
address = "dhcp"
530+
}
531+
}
532+
}
533+
network_interface {
534+
name = "vmbr0"
535+
}
536+
operating_system {
537+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
538+
type = "ubuntu"
539+
}
540+
}`, WithRootUser()),
541+
Check: resource.ComposeTestCheckFunc(
542+
ResourceAttributes(accTestContainerName, map[string]string{
543+
"initialization.0.hostname": "test-dns-issue",
544+
"initialization.0.dns.#": "0",
545+
}),
546+
),
547+
},
548+
{
549+
Config: te.RenderConfig(`
550+
resource "proxmox_virtual_environment_container" "test_container" {
551+
node_name = "{{.NodeName}}"
552+
unprivileged = true
553+
disk {
554+
datastore_id = "local-lvm"
555+
size = 4
556+
}
557+
initialization {
558+
hostname = "test-dns-issue"
559+
dns {}
560+
ip_config {
561+
ipv4 {
562+
address = "dhcp"
563+
}
564+
}
565+
}
566+
network_interface {
567+
name = "vmbr0"
568+
}
569+
operating_system {
570+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
571+
type = "ubuntu"
572+
}
573+
}`, WithRootUser()),
574+
Check: resource.ComposeTestCheckFunc(
575+
ResourceAttributes(accTestContainerName, map[string]string{
576+
"initialization.0.hostname": "test-dns-issue",
577+
"initialization.0.dns.#": "0",
578+
}),
579+
),
580+
},
581+
}},
582+
{"empty dns block on create", []resource.TestStep{
583+
{
584+
Config: te.RenderConfig(`
585+
resource "proxmox_virtual_environment_container" "test_container" {
586+
node_name = "{{.NodeName}}"
587+
unprivileged = true
588+
disk {
589+
datastore_id = "local-lvm"
590+
size = 4
591+
}
592+
initialization {
593+
hostname = "test-dns-create"
594+
dns {}
595+
ip_config {
596+
ipv4 {
597+
address = "dhcp"
598+
}
599+
}
600+
}
601+
network_interface {
602+
name = "vmbr0"
603+
}
604+
operating_system {
605+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
606+
type = "ubuntu"
607+
}
608+
}`, WithRootUser()),
609+
Check: resource.ComposeTestCheckFunc(
610+
ResourceAttributes(accTestContainerName, map[string]string{
611+
"initialization.0.hostname": "test-dns-create",
612+
"initialization.0.dns.#": "0",
613+
}),
614+
),
615+
},
616+
}},
617+
{"dns block with null values on create", []resource.TestStep{
618+
{
619+
Config: te.RenderConfig(`
620+
resource "proxmox_virtual_environment_container" "test_container" {
621+
node_name = "{{.NodeName}}"
622+
unprivileged = true
623+
disk {
624+
datastore_id = "local-lvm"
625+
size = 4
626+
}
627+
initialization {
628+
hostname = "test-dns-create"
629+
dns {
630+
domain = null
631+
server = ""
632+
servers = null
633+
}
634+
ip_config {
635+
ipv4 {
636+
address = "dhcp"
637+
}
638+
}
639+
}
640+
network_interface {
641+
name = "vmbr0"
642+
}
643+
operating_system {
644+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
645+
type = "ubuntu"
646+
}
647+
}`, WithRootUser()),
648+
Check: resource.ComposeTestCheckFunc(
649+
ResourceAttributes(accTestContainerName, map[string]string{
650+
"initialization.0.hostname": "test-dns-create",
651+
"initialization.0.dns.#": "0",
652+
}),
653+
),
654+
},
655+
}},
656+
{"dns block with null values on update", []resource.TestStep{
657+
{
658+
Config: te.RenderConfig(`
659+
resource "proxmox_virtual_environment_container" "test_container" {
660+
node_name = "{{.NodeName}}"
661+
unprivileged = true
662+
disk {
663+
datastore_id = "local-lvm"
664+
size = 4
665+
}
666+
initialization {
667+
hostname = "test-dns-update"
668+
dns {
669+
domain = "example.com"
670+
servers = ["8.8.8.8", "8.8.4.4"]
671+
}
672+
ip_config {
673+
ipv4 {
674+
address = "dhcp"
675+
}
676+
}
677+
}
678+
network_interface {
679+
name = "vmbr0"
680+
}
681+
operating_system {
682+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
683+
type = "ubuntu"
684+
}
685+
}`, WithRootUser()),
686+
Check: resource.ComposeTestCheckFunc(
687+
ResourceAttributes(accTestContainerName, map[string]string{
688+
"initialization.0.hostname": "test-dns-update",
689+
"initialization.0.dns.#": "1",
690+
"initialization.0.dns.0.domain": "example.com",
691+
"initialization.0.dns.0.servers.#": "2",
692+
"initialization.0.dns.0.servers.0": "8.8.8.8",
693+
"initialization.0.dns.0.servers.1": "8.8.4.4",
694+
}),
695+
),
696+
},
697+
{
698+
Config: te.RenderConfig(`
699+
resource "proxmox_virtual_environment_container" "test_container" {
700+
node_name = "{{.NodeName}}"
701+
unprivileged = true
702+
disk {
703+
datastore_id = "local-lvm"
704+
size = 4
705+
}
706+
initialization {
707+
hostname = "test-dns-update"
708+
dns {
709+
domain = ""
710+
servers = null
711+
}
712+
ip_config {
713+
ipv4 {
714+
address = "dhcp"
715+
}
716+
}
717+
}
718+
network_interface {
719+
name = "vmbr0"
720+
}
721+
operating_system {
722+
template_file_id = "local:vztmpl/{{.ImageFileName}}"
723+
type = "ubuntu"
724+
}
725+
}`, WithRootUser()),
726+
Check: resource.ComposeTestCheckFunc(
727+
ResourceAttributes(accTestContainerName, map[string]string{
728+
"initialization.0.hostname": "test-dns-update",
729+
"initialization.0.dns.#": "0",
730+
}),
731+
),
732+
},
733+
}},
515734
}
516735

517736
for _, tt := range tests {

proxmoxtf/resource/container/container.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -485,12 +485,12 @@ func Container() *schema.Resource {
485485
Description: "The list of DNS servers",
486486
Optional: true,
487487
Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validation.IsIPAddress},
488-
MinItems: 0,
488+
MinItems: 1,
489489
},
490490
},
491491
},
492-
MaxItems: 1,
493-
MinItems: 0,
492+
MaxItems: 1,
493+
DiffSuppressFunc: skipDnsDiffIfEmpty,
494494
},
495495
mkInitializationHostname: {
496496
Type: schema.TypeString,
@@ -3052,7 +3052,7 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
30523052
initializationBlock := initialization[0].(map[string]interface{})
30533053
initializationDNS := initializationBlock[mkInitializationDNS].([]interface{})
30543054

3055-
if len(initializationDNS) > 0 {
3055+
if len(initializationDNS) > 0 && initializationDNS[0] != nil {
30563056
initializationDNSBlock := initializationDNS[0].(map[string]interface{})
30573057
initializationDNSDomain = initializationDNSBlock[mkInitializationDNSDomain].(string)
30583058

@@ -3116,8 +3116,18 @@ func containerUpdate(ctx context.Context, d *schema.ResourceData, m interface{})
31163116
}
31173117

31183118
if d.HasChange(mkInitialization + ".0." + mkInitializationDNS) {
3119-
updateBody.DNSDomain = &initializationDNSDomain
3120-
updateBody.DNSServer = &initializationDNSServer
3119+
if initializationDNSDomain != "" {
3120+
updateBody.DNSDomain = &initializationDNSDomain
3121+
} else {
3122+
updateBody.Delete = append(updateBody.Delete, "searchdomain")
3123+
}
3124+
3125+
if initializationDNSServer != "" {
3126+
updateBody.DNSServer = &initializationDNSServer
3127+
} else {
3128+
updateBody.Delete = append(updateBody.Delete, "nameserver")
3129+
}
3130+
31213131
rebootRequired = true
31223132
}
31233133

@@ -3527,3 +3537,19 @@ func parseImportIDWithNodeName(id string) (string, string, error) {
35273537
func getContainerDiskVolume(rawVolume string, vmID int, diskID int) string {
35283538
return fmt.Sprintf("%s:vm-%d-disk-%d", rawVolume, vmID, diskID)
35293539
}
3540+
3541+
func skipDnsDiffIfEmpty(k, oldValue, newValue string, d *schema.ResourceData) bool {
3542+
dnsDataKey := mkInitialization + ".0." + mkInitializationDNS
3543+
if k == dnsDataKey+".#" {
3544+
if oldValue == "0" && newValue == "1" {
3545+
// if dns block's attributes are empty, do not report change
3546+
domain := d.Get(dnsDataKey + ".0." + mkInitializationDNSDomain).(string)
3547+
server := d.Get(dnsDataKey + ".0." + mkInitializationDNSServer).(string)
3548+
servers := d.Get(dnsDataKey + ".0." + mkInitializationDNSServers).([]interface{})
3549+
3550+
return domain == "" && server == "" && len(servers) == 0
3551+
}
3552+
}
3553+
3554+
return false
3555+
}

proxmoxtf/resource/container/container_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ package resource
99
import (
1010
"testing"
1111

12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
1215
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1316

1417
"github.com/bpg/terraform-provider-proxmox/proxmoxtf/test"
@@ -340,3 +343,41 @@ func TestContainerSchema(t *testing.T) {
340343
mkOperatingSystemType: schema.TypeString,
341344
})
342345
}
346+
347+
func TestInitializationDnsBlockDiffIgnore(t *testing.T) {
348+
t.Parallel()
349+
350+
container := Container()
351+
352+
tests := []struct {
353+
domain string
354+
server string
355+
servers []string
356+
expected bool
357+
}{
358+
{"somedomain", "", []string{}, false},
359+
{"somedomain", "127.0.0.1", []string{}, false},
360+
{"somedomain", "", []string{"127.0.0.1"}, false},
361+
{"", "127.0.0.1", []string{}, false},
362+
{"", "", []string{"127.0.0.1"}, false},
363+
{"", "", []string{}, true},
364+
}
365+
366+
for _, tt := range tests {
367+
d := container.TestResourceData()
368+
dnsBlockKey := mkInitialization + ".0." + mkInitializationDNS
369+
m := make(map[string]any)
370+
m[mkInitializationDNS] = []any{
371+
map[string]any{
372+
mkInitializationDNSDomain: tt.domain,
373+
mkInitializationDNSServer: tt.server,
374+
mkInitializationDNSServers: tt.servers,
375+
},
376+
}
377+
err := d.Set(mkInitialization, []any{m})
378+
require.NoError(t, err)
379+
380+
actual := skipDnsDiffIfEmpty(dnsBlockKey+".#", "0", "1", d)
381+
assert.Equal(t, tt.expected, actual)
382+
}
383+
}

0 commit comments

Comments
 (0)