Skip to content

Commit 93878c0

Browse files
mcanevetsmira
authored andcommitted
fix(machined): align OpenNebula hostname precedence with reference
Use SET_HOSTNAME exclusively, matching the reference net-15-hostname script. The previous implementation fell back to HOSTNAME (not used by OpenNebula) and NAME (the VM name, not a hostname source in the reference). DNS_HOSTNAME is a server-side flag that triggers a reverse DNS lookup — a live network operation that cannot be performed inside ParseMetadata. Signed-off-by: Mickaël Canévet <mickael.canevet@proton.ch> Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com> (cherry picked from commit 4f4ec98)
1 parent 9718d73 commit 93878c0

File tree

4 files changed

+52
-48
lines changed

4 files changed

+52
-48
lines changed

internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/hostname_test.go

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,45 @@ func TestSanitizeHostname(t *testing.T) {
3030

3131
for _, tc := range []struct {
3232
name string
33-
nameVar string
33+
setHostname string
3434
wantHostname string
3535
wantDomainname string
3636
}{
3737
{
3838
name: "clean hostname passes through unchanged",
39-
nameVar: "myhost",
39+
setHostname: "myhost",
4040
wantHostname: "myhost",
4141
wantDomainname: "",
4242
},
4343
{
4444
name: "FQDN is split on first dot",
45-
nameVar: "myhost.example.com",
45+
setHostname: "myhost.example.com",
4646
wantHostname: "myhost",
4747
wantDomainname: "example.com",
4848
},
4949
{
5050
name: "invalid chars replaced with hyphen",
51-
nameVar: "my_host",
51+
setHostname: "my_host",
5252
wantHostname: "my-host",
5353
wantDomainname: "",
5454
},
5555
{
5656
name: "leading and trailing hyphens stripped",
57-
nameVar: "-myhost-",
57+
setHostname: "-myhost-",
5858
wantHostname: "myhost",
5959
wantDomainname: "",
6060
},
6161
{
6262
name: "per-label hyphen trimming",
63-
nameVar: "my-.host",
63+
setHostname: "my-.host",
6464
wantHostname: "my",
6565
wantDomainname: "host",
6666
},
6767
} {
6868
t.Run(tc.name, func(t *testing.T) {
6969
t.Parallel()
7070

71-
ctx := minimalContext("NAME = \"" + tc.nameVar + "\"")
71+
ctx := minimalContext("SET_HOSTNAME = \"" + tc.setHostname + "\"")
7272

7373
networkConfig, err := o.ParseMetadata(st, ctx)
7474
require.NoError(t, err)
@@ -79,10 +79,10 @@ func TestSanitizeHostname(t *testing.T) {
7979
})
8080
}
8181

82-
t.Run("empty string produces no hostname entry", func(t *testing.T) {
82+
t.Run("empty SET_HOSTNAME produces no hostname entry", func(t *testing.T) {
8383
t.Parallel()
8484

85-
ctx := minimalContext("NAME = \"\"")
85+
ctx := minimalContext("SET_HOSTNAME = \"\"")
8686

8787
networkConfig, err := o.ParseMetadata(st, ctx)
8888
require.NoError(t, err)
@@ -99,38 +99,48 @@ func TestParseMetadataHostname(t *testing.T) {
9999
for _, tc := range []struct {
100100
name string
101101
vars string
102+
wantHostnames int
102103
wantHostname string
103104
wantDomainname string
104105
}{
105106
{
106-
name: "HOSTNAME takes priority",
107-
vars: "HOSTNAME = \"fromhostname\"\nSET_HOSTNAME = \"fromsethostname\"\nNAME = \"fromname\"",
108-
wantHostname: "fromhostname",
109-
wantDomainname: "",
107+
name: "SET_HOSTNAME is used as hostname",
108+
vars: "SET_HOSTNAME = \"myhost\"",
109+
wantHostnames: 1,
110+
wantHostname: "myhost",
110111
},
111112
{
112-
name: "falls back to SET_HOSTNAME when HOSTNAME is empty",
113-
vars: "SET_HOSTNAME = \"fromsethostname\"\nNAME = \"fromname\"",
114-
wantHostname: "fromsethostname",
115-
wantDomainname: "",
113+
name: "FQDN in SET_HOSTNAME is split into Hostname and Domainname",
114+
vars: "SET_HOSTNAME = \"myhost.example.com\"",
115+
wantHostnames: 1,
116+
wantHostname: "myhost",
117+
wantDomainname: "example.com",
116118
},
117119
{
118-
name: "falls back to NAME when both HOSTNAME and SET_HOSTNAME are empty",
119-
vars: "NAME = \"fromname\"",
120-
wantHostname: "fromname",
121-
wantDomainname: "",
120+
name: "HOSTNAME variable is ignored",
121+
vars: "HOSTNAME = \"fromhostname\"",
122+
wantHostnames: 0,
122123
},
123124
{
124-
name: "DNS_HOSTNAME=YES is not used as Domainname",
125-
vars: "NAME = \"myhost\"\nDNS_HOSTNAME = \"YES\"",
126-
wantHostname: "myhost",
127-
wantDomainname: "",
125+
name: "NAME variable is ignored",
126+
vars: "NAME = \"fromname\"",
127+
wantHostnames: 0,
128128
},
129129
{
130-
name: "FQDN in NAME is split into Hostname and Domainname",
131-
vars: "NAME = \"myhost.example.com\"",
132-
wantHostname: "myhost",
133-
wantDomainname: "example.com",
130+
name: "SET_HOSTNAME takes precedence over HOSTNAME and NAME",
131+
vars: "SET_HOSTNAME = \"correct\"\nHOSTNAME = \"wrong\"\nNAME = \"alsowrong\"",
132+
wantHostnames: 1,
133+
wantHostname: "correct",
134+
},
135+
{
136+
name: "DNS_HOSTNAME=YES is not used as a hostname value",
137+
vars: "DNS_HOSTNAME = \"YES\"",
138+
wantHostnames: 0,
139+
},
140+
{
141+
name: "absent SET_HOSTNAME produces no hostname entry",
142+
vars: "",
143+
wantHostnames: 0,
134144
},
135145
} {
136146
t.Run(tc.name, func(t *testing.T) {
@@ -140,10 +150,12 @@ func TestParseMetadataHostname(t *testing.T) {
140150

141151
networkConfig, err := o.ParseMetadata(st, ctx)
142152
require.NoError(t, err)
143-
require.Len(t, networkConfig.Hostnames, 1)
153+
require.Len(t, networkConfig.Hostnames, tc.wantHostnames)
144154

145-
assert.Equal(t, tc.wantHostname, networkConfig.Hostnames[0].Hostname)
146-
assert.Equal(t, tc.wantDomainname, networkConfig.Hostnames[0].Domainname)
155+
if tc.wantHostnames > 0 {
156+
assert.Equal(t, tc.wantHostname, networkConfig.Hostnames[0].Hostname)
157+
assert.Equal(t, tc.wantDomainname, networkConfig.Hostnames[0].Domainname)
158+
}
147159
})
148160
}
149161
}

internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/opennebula.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -648,21 +648,13 @@ func ethInterfaceName(key string) (string, bool) {
648648
return name, true
649649
}
650650

651-
// resolveHostname picks the best hostname value from the context map and
652-
// sanitizes it. Precedence: HOSTNAME > SET_HOSTNAME > NAME.
651+
// resolveHostname reads SET_HOSTNAME from the context map and sanitizes it,
652+
// matching the reference net-15-hostname script precedence. HOSTNAME and NAME
653+
// are not used — the reference never reads them for hostname configuration.
654+
// DNS_HOSTNAME is a server-side flag that triggers a reverse DNS lookup
655+
// (a live network operation) and cannot be honored inside ParseMetadata.
653656
func resolveHostname(oneContext map[string]string) string {
654-
// HOSTNAME is checked first (deviation from the reference which tries
655-
// SET_HOSTNAME before HOSTNAME) to preserve backward compatibility with
656-
// existing Talos deployments that rely on the OpenNebula-injected FQDN.
657-
v := oneContext["HOSTNAME"]
658-
if v == "" {
659-
v = oneContext["SET_HOSTNAME"]
660-
if v == "" {
661-
v = oneContext["NAME"]
662-
}
663-
}
664-
665-
return sanitizeHostname(v)
657+
return sanitizeHostname(oneContext["SET_HOSTNAME"])
666658
}
667659

668660
// ParseMetadata converts opennebula metadata to platform network config.

internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ VMID = "14"
3636
ETH1_MAC = "02:00:c0:a8:01:5d"
3737
ETH1_METHOD = "dhcp"
3838
ETH1_METRIC = "200"
39-
NAME = "code-server"
39+
SET_HOSTNAME = "code-server"

internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/metadata_no_network_flag.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ VMID = "14"
3838
ETH1_MAC = "02:00:c0:a8:01:5d"
3939
ETH1_METHOD = "dhcp"
4040
ETH1_METRIC = "200"
41-
NAME = "code-server"
41+
SET_HOSTNAME = "code-server"

0 commit comments

Comments
 (0)