Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions coreos-cloudinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"log"
"os"
"runtime"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -285,6 +286,14 @@ func determineHostname(md datasource.Metadata, udata *initialize.UserData) strin
hostname = udataHostname
}
}
if len(hostname) > 63 {
Copy link
Member

@gabriel-samfira gabriel-samfira Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a discussion at some point about using the FQDN vs the short name as the hostname (and potentially adding the fqdn in /etc/hosts). Some projects (like afterburn) prefer to use the FQDN, some projects prefer the short name.

I think that if the hostname is too large, we should make an attempt to use the short name. After which we should truncate the short name if it continues to be too large.

The reason is that this way, we at least get a valid hostname, and not a truncated FQDN (if the short name is within the 63 character limit). The full FQDN will still be valid if set in /etc/hosts along side the short name (if each element of the hostname is itself valid).

@jepio @RiRa12621 what do you folks think?

Copy link
Member

@gabriel-samfira gabriel-samfira Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, if we have something like this:

#cloud-config
hostname: this-hostname-is-precisely-than-sixty-three-characters-in--size.example.com

And we truncate at 63 using the logic here, we get: this-hostname-is-precisely-than-sixty-three-characters-in--size. Which is fine.

But if we have:

#cloud-config
hostname: this-hostname-is-a-bit-larger-than-sixty-three-characters.example.com

we end up with: this-hostname-is-a-bit-larger-than-sixty-three-characters.examp. Which is neither the FQDN that we want, nor a short name. If we go with the short name approach, we at least end up with a valid short name of this-hostname-is-a-bit-larger-than-sixty-three-characters, and we can set the correct FQDN in /etc/hosts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the second example, the code does the split on . before truncating, so the outcome is exactly as you describe (we don't end up with a partial FQDN).

I think in general the hostname and (/etc/hostname) should be just the first label, and the FQDN should be resolved through DNS.

cloud-init and coreos-cloudinit support manage_etc_hosts: true for those who need it.

log.Printf("Hostname too long. Truncating hostname %s to %s", hostname, strings.Split(hostname, ".")[0])
hostname = strings.Split(hostname, ".")[0]
if len(hostname) > 63 {
log.Printf("Hostname still too long. Truncating hostname %s further to 63 bytes (%s)", hostname, hostname[:63])
hostname = hostname[:63]
}
}
return hostname
}

Expand Down
76 changes: 76 additions & 0 deletions coreos-cloudinit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import (
"bytes"
"encoding/base64"
"errors"
"github.com/flatcar/coreos-cloudinit/datasource"
"github.com/flatcar/coreos-cloudinit/initialize"
"net"
"reflect"
"testing"
)

Expand Down Expand Up @@ -75,3 +79,75 @@ func TestDecompressIfGzip(t *testing.T) {
}

}

func TestDetermineHostname(t *testing.T) {
for _, tt := range []struct {
metaData datasource.Metadata
uData *initialize.UserData
expect string
}{
{
metaData: datasource.Metadata{
PublicIPv4: net.ParseIP("1.2.3.4"),
PublicIPv6: net.ParseIP("5.6.7.8"),
PrivateIPv4: net.ParseIP("1.2.3.4"),
PrivateIPv6: net.ParseIP("5.6.7.8"),
Hostname: "regular-name",
SSHPublicKeys: map[string]string{"my": "key"},
NetworkConfig: net.Interface{
Index: 0,
MTU: 0,
Name: "some-interface",
HardwareAddr: nil,
Flags: 0,
},
},
uData: nil,
expect: "regular-name",
},
{
metaData: datasource.Metadata{
PublicIPv4: net.ParseIP("1.2.3.4"),
PublicIPv6: net.ParseIP("5.6.7.8"),
PrivateIPv4: net.ParseIP("1.2.3.4"),
PrivateIPv6: net.ParseIP("5.6.7.8"),
Hostname: "this-hostname-is-larger-than-sixty-three-characters-long-and.will.be.truncated.locale",
SSHPublicKeys: map[string]string{"my": "key"},
NetworkConfig: net.Interface{
Index: 0,
MTU: 0,
Name: "some-interface",
HardwareAddr: nil,
Flags: 0,
},
},
uData: nil,
expect: "this-hostname-is-larger-than-sixty-three-characters-long-and",
},
{
metaData: datasource.Metadata{
PublicIPv4: net.ParseIP("1.2.3.4"),
PublicIPv6: net.ParseIP("5.6.7.8"),
PrivateIPv4: net.ParseIP("1.2.3.4"),
PrivateIPv6: net.ParseIP("5.6.7.8"),
Hostname: "this-hostname-is-larger-than-sixty-three-characters-long-and-will-be-truncated.local",
SSHPublicKeys: map[string]string{"my": "key"},
NetworkConfig: net.Interface{
Index: 0,
MTU: 0,
Name: "some-interface",
HardwareAddr: nil,
Flags: 0,
},
},
uData: nil,
expect: "this-hostname-is-larger-than-sixty-three-characters-long-and-wi",
},
} {
hostname := determineHostname(tt.metaData, tt.uData)
if !reflect.DeepEqual(tt.expect, hostname) {
t.Fatalf("Bad hostname, want %s, got %s", tt.expect, hostname)
}

}
}
5 changes: 0 additions & 5 deletions datasource/metadata/ec2/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ func (ms metadataService) FetchMetadata() (datasource.Metadata, error) {
}

if hostname, err := ms.fetchAttribute(fmt.Sprintf("%s/hostname", ms.MetadataUrl())); err == nil {
hostname := strings.Split(hostname, ".")[0]
if len(hostname) > 63 {
log.Printf("Truncating hostname %s to 63 bytes (%s)", hostname, hostname[:63])
hostname = hostname[:63]
}
metadata.Hostname = hostname
} else if _, ok := err.(pkg.ErrNotFound); !ok {
return metadata, err
Expand Down
20 changes: 1 addition & 19 deletions datasource/metadata/ec2/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,25 +188,7 @@ func TestFetchMetadata(t *testing.T) {
"/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
},
expect: datasource.Metadata{
Hostname: "host",
PrivateIPv4: net.ParseIP("1.2.3.4"),
PublicIPv4: net.ParseIP("5.6.7.8"),
SSHPublicKeys: map[string]string{"test1": "key"},
},
},
{
root: "/",
metadataPath: "2009-04-04/meta-data",
resources: map[string]string{
"/2009-04-04/meta-data/hostname": "this-hostname-is-larger-than-sixty-three-characters-long-and-will-be-truncated.local",
"/2009-04-04/meta-data/local-ipv4": "1.2.3.4",
"/2009-04-04/meta-data/public-ipv4": "5.6.7.8",
"/2009-04-04/meta-data/public-keys": "0=test1\n",
"/2009-04-04/meta-data/public-keys/0": "openssh-key",
"/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
},
expect: datasource.Metadata{
Hostname: "this-hostname-is-larger-than-sixty-three-characters-long-and-wi",
Hostname: "host.local",
PrivateIPv4: net.ParseIP("1.2.3.4"),
PublicIPv4: net.ParseIP("5.6.7.8"),
SSHPublicKeys: map[string]string{"test1": "key"},
Expand Down