Skip to content

Commit

Permalink
return service unavailable from k0s api when etcd is unhealthy
Browse files Browse the repository at this point in the history
Signed-off-by: Ethan Mosbaugh <[email protected]>
  • Loading branch information
emosbaugh committed Nov 5, 2024
1 parent 93eb6d1 commit 9706878
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
6 changes: 6 additions & 0 deletions cmd/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ func (c *command) etcdHandler() http.Handler {
return
}

err = etcdClient.Health(ctx)
if err != nil {
sendError(err, resp, http.StatusServiceUnavailable)
return
}

memberList, err := etcdClient.AddMember(ctx, etcdReq.Node, etcdReq.PeerAddress)
if err != nil {
sendError(err, resp)
Expand Down
9 changes: 9 additions & 0 deletions pkg/token/joinclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,23 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"

"github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
"github.com/k0sproject/k0s/pkg/kubernetes"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
)

var (
ErrEtcdUnhealthy = errors.New("etcd is unhealthy")
)

// JoinClient is the client we can use to call k0s join APIs
type JoinClient struct {
joinTokenType string
Expand Down Expand Up @@ -101,6 +107,9 @@ func (j *JoinClient) JoinEtcd(ctx context.Context, etcdRequest v1beta1.EtcdReque
if err == nil {
err = json.Unmarshal(b, &etcdResponse)
}
if apierrors.IsServiceUnavailable(err) {
return etcdResponse, ErrEtcdUnhealthy
}

return etcdResponse, err
}
28 changes: 24 additions & 4 deletions pkg/token/joinclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@ func TestJoinClient_Cancellation(t *testing.T) {
name string
funcUnderTest func(context.Context, *token.JoinClient) error
}{
{"GetCA", func(ctx context.Context, c *token.JoinClient) error {
_, err := c.GetCA(ctx)
return err
}},
{"JoinEtcd", func(ctx context.Context, c *token.JoinClient) error {
_, err := c.JoinEtcd(ctx, k0sv1beta1.EtcdRequest{})
return err
Expand Down Expand Up @@ -140,6 +136,30 @@ func TestJoinClient_Cancellation(t *testing.T) {
}
}

func TestJoinClient_EtcdUnhealthy(t *testing.T) {
t.Parallel()

joinURL, certData := startFakeJoinServer(t, func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusServiceUnavailable)
})

joinURL.Path = "/some/sub/path"
kubeconfig, err := token.GenerateKubeconfig(joinURL.String(), certData, t.Name(), "the-token")
require.NoError(t, err)
tok, err := token.JoinEncode(bytes.NewReader(kubeconfig))
require.NoError(t, err)

underTest, err := token.JoinClientFromToken(tok)
require.NoError(t, err)

response, err := underTest.JoinEtcd(context.TODO(), k0sv1beta1.EtcdRequest{
Node: "the-node",
PeerAddress: "the-peer-address",
})
assert.ErrorIs(t, err, token.ErrEtcdUnhealthy)
assert.Zero(t, response)
}

func startFakeJoinServer(t *testing.T, handler func(http.ResponseWriter, *http.Request)) (*url.URL, []byte) {
requestCtx, cancelRequests := context.WithCancel(context.Background())
var ok bool
Expand Down

0 comments on commit 9706878

Please sign in to comment.