Skip to content

Commit

Permalink
Move Windows specific things into their own files
Browse files Browse the repository at this point in the history
So that they are only compiled on Windows.

Signed-off-by: Tom Wieczorek <[email protected]>
  • Loading branch information
twz123 committed Nov 26, 2024
1 parent 99034e9 commit 38f45c6
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 85 deletions.
31 changes: 2 additions & 29 deletions pkg/node/nodename.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ package node
import (
"context"
"fmt"
"runtime"
"time"

"github.com/carlmjohnson/requests"
"github.com/k0sproject/k0s/pkg/k0scontext"
nodeutil "k8s.io/component-helpers/node/util"
)

Expand All @@ -32,36 +28,13 @@ func GetNodename(override string) (string, error) {
return getNodename(context.TODO(), override)
}

// A URL that may be retrieved to determine the nodename.
type nodenameURL string

func getNodename(ctx context.Context, override string) (string, error) {
if override == "" && runtime.GOOS == "windows" {
// we need to check if we have EC2 dns name available
override = getHostnameFromAwsMeta(ctx)
if override == "" {
override = defaultNodenameOverride(ctx)
}
nodeName, err := nodeutil.GetHostname(override)
if err != nil {
return "", fmt.Errorf("failed to determine node name: %w", err)
}
return nodeName, nil
}

func getHostnameFromAwsMeta(ctx context.Context) string {
const awsMetaInformationHostnameURL nodenameURL = "http://169.254.169.254/latest/meta-data/local-hostname"
url := k0scontext.ValueOr(ctx, awsMetaInformationHostnameURL)

ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()

var s string
err := requests.
URL(string(url)).
ToString(&s).
Fetch(ctx)
// if status code is 2XX and no transport error, we assume we are running on ec2
if err != nil {
return ""
}
return s
}
27 changes: 27 additions & 0 deletions pkg/node/nodename_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build !windows

/*
Copyright 2023 k0s authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
"context"
)

func defaultNodenameOverride(context.Context) string {
return "" // no default override
}
59 changes: 3 additions & 56 deletions pkg/node/nodename_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,15 @@ limitations under the License.
package node

import (
"context"
"net"
"net/http"
"net/url"
"runtime"
"testing"

"github.com/k0sproject/k0s/pkg/k0scontext"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
nodeutil "k8s.io/component-helpers/node/util"
)

func TestGetNodename(t *testing.T) {
kubeHostname, err := nodeutil.GetHostname("")
require.NoError(t, err)

t.Run("should_always_return_override_if_given", func(t *testing.T) {
name, err := GetNodename("override")
if assert.NoError(t, err) {
Expand All @@ -42,59 +34,14 @@ func TestGetNodename(t *testing.T) {
})

if runtime.GOOS != "windows" {
kubeHostname, err := nodeutil.GetHostname("")
require.NoError(t, err)

t.Run("should_call_kubernetes_hostname_helper_on_linux", func(t *testing.T) {
name, err := GetNodename("")
if assert.NoError(t, err) {
assert.Equal(t, kubeHostname, name)
}
})
} else {
baseURL := startFakeMetadataServer(t)

t.Run("windows_no_metadata_service_available", func(t *testing.T) {
ctx := k0scontext.WithValue(context.TODO(), nodenameURL(baseURL))
name, err := getNodename(ctx, "")
if assert.NoError(t, err) {
assert.Equal(t, kubeHostname, name)
}
})

t.Run("windows_metadata_service_is_available", func(t *testing.T) {
ctx := k0scontext.WithValue(context.TODO(), nodenameURL(baseURL+"/latest/meta-data/local-hostname"))
name, err := getNodename(ctx, "")
if assert.NoError(t, err) {
assert.Equal(t, "some-hostname from aws_metadata", name)
}
})
}
}

func startFakeMetadataServer(t *testing.T) string {
mux := http.NewServeMux()
mux.HandleFunc("/latest/meta-data/local-hostname", func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte("Some-hostname from AWS_metadata\n"))
assert.NoError(t, err)
})
server := &http.Server{Addr: "localhost:0", Handler: mux}
listener, err := net.Listen("tcp", server.Addr)
if err != nil {
require.NoError(t, err)
}

serverError := make(chan error)
go func() {
defer close(serverError)
serverError <- server.Serve(listener)
}()

t.Cleanup(func() {
err := server.Shutdown(context.Background())
if !assert.NoError(t, err, "Couldn't shutdown HTTP server") {
return
}

assert.ErrorIs(t, <-serverError, http.ErrServerClosed, "HTTP server terminated unexpectedly")
})

return (&url.URL{Scheme: "http", Host: listener.Addr().String()}).String()
}
48 changes: 48 additions & 0 deletions pkg/node/nodename_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2024 k0s authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
"context"
"time"

"github.com/k0sproject/k0s/pkg/k0scontext"

"github.com/carlmjohnson/requests"
)

// A URL that may be retrieved to determine the nodename.
type nodenameURL string

func defaultNodenameOverride(ctx context.Context) string {
// we need to check if we have EC2 dns name available
url := k0scontext.ValueOr[nodenameURL](ctx, "http://169.254.169.254/latest/meta-data/local-hostname")

ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()

var s string
err := requests.
URL(string(url)).
ToString(&s).
Fetch(ctx)
// if status code is 2XX and no transport error, we assume we are running on ec2
if err != nil {
return ""
}
return s
}
82 changes: 82 additions & 0 deletions pkg/node/nodename_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
Copyright 2024 k0s authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
"context"
"net"
"net/http"
"net/url"
"testing"

"github.com/k0sproject/k0s/pkg/k0scontext"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
nodeutil "k8s.io/component-helpers/node/util"
)

func TestGetNodenameWindows(t *testing.T) {
kubeHostname, err := nodeutil.GetHostname("")
require.NoError(t, err)
baseURL := startFakeMetadataServer(t)

t.Run("no_metadata_service_available", func(t *testing.T) {
ctx := k0scontext.WithValue(context.TODO(), nodenameURL(baseURL))
name, err := getNodename(ctx, "")
if assert.NoError(t, err) {
assert.Equal(t, kubeHostname, name)
}
})

t.Run("metadata_service_is_available", func(t *testing.T) {
ctx := k0scontext.WithValue(context.TODO(), nodenameURL(baseURL+"/latest/meta-data/local-hostname"))
name, err := getNodename(ctx, "")
if assert.NoError(t, err) {
assert.Equal(t, "some-hostname from aws_metadata", name)
}
})
}

func startFakeMetadataServer(t *testing.T) string {
mux := http.NewServeMux()
mux.HandleFunc("/latest/meta-data/local-hostname", func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte("Some-hostname from AWS_metadata\n"))
assert.NoError(t, err)
})
server := &http.Server{Addr: "localhost:0", Handler: mux}
listener, err := net.Listen("tcp", server.Addr)
if err != nil {
require.NoError(t, err)
}

serverError := make(chan error)
go func() {
defer close(serverError)
serverError <- server.Serve(listener)
}()

t.Cleanup(func() {
err := server.Shutdown(context.Background())
if !assert.NoError(t, err, "Couldn't shutdown HTTP server") {
return
}

assert.ErrorIs(t, <-serverError, http.ErrServerClosed, "HTTP server terminated unexpectedly")
})

return (&url.URL{Scheme: "http", Host: listener.Addr().String()}).String()
}

0 comments on commit 38f45c6

Please sign in to comment.