Skip to content

Commit 6be0f91

Browse files
authored
Merge pull request #2 from marcnuri-forks/review/kiali
2 parents e7f6ff9 + 504303a commit 6be0f91

File tree

8 files changed

+167
-208
lines changed

8 files changed

+167
-208
lines changed

pkg/kiali/kiali.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,41 @@ import (
55
"crypto/tls"
66
"fmt"
77
"io"
8-
"k8s.io/klog/v2"
98
"net/http"
109
"net/url"
1110
"strings"
11+
12+
"github.com/containers/kubernetes-mcp-server/pkg/config"
13+
"k8s.io/client-go/rest"
14+
"k8s.io/klog/v2"
1215
)
1316

1417
type Kiali struct {
15-
manager *Manager
18+
bearerToken string
19+
kialiURL string
20+
kialiInsecure bool
1621
}
1722

18-
func (m *Manager) GetKiali() *Kiali {
19-
return &Kiali{manager: m}
20-
}
21-
22-
func (k *Kiali) GetKiali() *Kiali {
23-
return k
23+
// NewKiali creates a new Kiali instance
24+
func NewKiali(config *config.StaticConfig, kubernetes *rest.Config) *Kiali {
25+
kiali := &Kiali{bearerToken: kubernetes.BearerToken}
26+
if cfg, ok := config.GetToolsetConfig("kiali"); ok {
27+
if kc, ok := cfg.(*Config); ok && kc != nil {
28+
kiali.kialiURL = kc.Url
29+
kiali.kialiInsecure = kc.Insecure
30+
}
31+
}
32+
return kiali
2433
}
2534

2635
// validateAndGetURL validates the Kiali client configuration and returns the full URL
2736
// by safely concatenating the base URL with the provided endpoint, avoiding duplicate
2837
// or missing slashes regardless of trailing/leading slashes.
2938
func (k *Kiali) validateAndGetURL(endpoint string) (string, error) {
30-
if k == nil || k.manager == nil || k.manager.KialiURL == "" {
39+
if k == nil || k.kialiURL == "" {
3140
return "", fmt.Errorf("kiali client not initialized")
3241
}
33-
baseStr := strings.TrimSpace(k.manager.KialiURL)
42+
baseStr := strings.TrimSpace(k.kialiURL)
3443
if baseStr == "" {
3544
return "", fmt.Errorf("kiali server URL not configured")
3645
}
@@ -52,7 +61,7 @@ func (k *Kiali) createHTTPClient() *http.Client {
5261
return &http.Client{
5362
Transport: &http.Transport{
5463
TLSClientConfig: &tls.Config{
55-
InsecureSkipVerify: k.manager.KialiInsecure,
64+
InsecureSkipVerify: k.kialiInsecure,
5665
},
5766
},
5867
}
@@ -62,10 +71,10 @@ func (k *Kiali) createHTTPClient() *http.Client {
6271
// Kiali client is currently configured to use (Bearer <token>), or empty
6372
// if no bearer token is configured.
6473
func (k *Kiali) authorizationHeader() string {
65-
if k == nil || k.manager == nil {
74+
if k == nil {
6675
return ""
6776
}
68-
token := strings.TrimSpace(k.manager.BearerToken)
77+
token := strings.TrimSpace(k.bearerToken)
6978
if token == "" {
7079
return ""
7180
}

pkg/kiali/kiali_test.go

Lines changed: 104 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,126 @@
11
package kiali
22

33
import (
4-
"context"
4+
"fmt"
55
"net/http"
6-
"net/http/httptest"
76
"net/url"
87
"testing"
98

9+
"github.com/containers/kubernetes-mcp-server/internal/test"
1010
"github.com/containers/kubernetes-mcp-server/pkg/config"
11+
"github.com/stretchr/testify/suite"
1112
)
1213

13-
func TestValidateAndGetURL_JoinsProperly(t *testing.T) {
14-
cfg := config.Default()
15-
cfg.SetToolsetConfig("kiali", &Config{Url: "https://kiali.example/"})
16-
m := NewManager(cfg)
17-
k := m.GetKiali()
18-
19-
full, err := k.validateAndGetURL("/api/path")
20-
if err != nil {
21-
t.Fatalf("unexpected error: %v", err)
22-
}
23-
if full != "https://kiali.example/api/path" {
24-
t.Fatalf("unexpected url: %s", full)
25-
}
26-
27-
m.KialiURL = "https://kiali.example"
28-
full, err = k.validateAndGetURL("api/path")
29-
if err != nil {
30-
t.Fatalf("unexpected error: %v", err)
31-
}
32-
if full != "https://kiali.example/api/path" {
33-
t.Fatalf("unexpected url: %s", full)
34-
}
35-
36-
// preserve query
37-
m.KialiURL = "https://kiali.example"
38-
full, err = k.validateAndGetURL("/api/path?x=1&y=2")
39-
if err != nil {
40-
t.Fatalf("unexpected error: %v", err)
41-
}
42-
u, _ := url.Parse(full)
43-
if u.Path != "/api/path" || u.Query().Get("x") != "1" || u.Query().Get("y") != "2" {
44-
t.Fatalf("unexpected parsed url: %s", full)
45-
}
14+
type KialiSuite struct {
15+
suite.Suite
16+
MockServer *test.MockServer
17+
Config *config.StaticConfig
18+
}
19+
20+
func (s *KialiSuite) SetupTest() {
21+
s.MockServer = test.NewMockServer()
22+
s.MockServer.Config().BearerToken = ""
23+
s.Config = config.Default()
24+
}
25+
26+
func (s *KialiSuite) TearDownTest() {
27+
s.MockServer.Close()
28+
}
29+
30+
func (s *KialiSuite) TestNewKiali_SetsFields() {
31+
s.Config = test.Must(config.ReadToml([]byte(`
32+
[toolset_configs.kiali]
33+
url = "https://kiali.example/"
34+
insecure = true
35+
`)))
36+
s.MockServer.Config().BearerToken = "bearer-token"
37+
k := NewKiali(s.Config, s.MockServer.Config())
38+
39+
s.Run("URL is set", func() {
40+
s.Equal("https://kiali.example/", k.kialiURL, "Unexpected Kiali URL")
41+
})
42+
s.Run("Insecure is set", func() {
43+
s.True(k.kialiInsecure, "Expected Kiali Insecure to be true")
44+
})
45+
s.Run("BearerToken is set", func() {
46+
s.Equal("bearer-token", k.bearerToken, "Unexpected Kiali BearerToken")
47+
})
48+
}
49+
50+
func (s *KialiSuite) TestNewKiali_InvalidConfig() {
51+
cfg, err := config.ReadToml([]byte(`
52+
[toolset_configs.kiali]
53+
url = "://invalid-url"
54+
`))
55+
s.Error(err, "Expected error reading invalid config")
56+
s.ErrorContains(err, "kiali-url must be a valid URL", "Unexpected error message")
57+
s.Nil(cfg, "Unexpected Kiali config")
58+
}
59+
60+
func (s *KialiSuite) TestValidateAndGetURL() {
61+
s.Config = test.Must(config.ReadToml([]byte(`
62+
[toolset_configs.kiali]
63+
url = "https://kiali.example/"
64+
`)))
65+
k := NewKiali(s.Config, s.MockServer.Config())
66+
67+
s.Run("Computes full URL", func() {
68+
s.Run("with leading slash", func() {
69+
full, err := k.validateAndGetURL("/api/path")
70+
s.Require().NoError(err, "Expected no error validating URL")
71+
s.Equal("https://kiali.example/api/path", full, "Unexpected full URL")
72+
})
73+
74+
s.Run("without leading slash", func() {
75+
full, err := k.validateAndGetURL("api/path")
76+
s.Require().NoError(err, "Expected no error validating URL")
77+
s.Equal("https://kiali.example/api/path", full, "Unexpected full URL")
78+
})
79+
80+
s.Run("with query parameters, preserves query", func() {
81+
full, err := k.validateAndGetURL("/api/path?x=1&y=2")
82+
s.Require().NoError(err, "Expected no error validating URL")
83+
u, err := url.Parse(full)
84+
s.Require().NoError(err, "Expected to parse full URL")
85+
s.Equal("/api/path", u.Path, "Unexpected path in parsed URL")
86+
s.Equal("1", u.Query().Get("x"), "Unexpected query parameter x")
87+
s.Equal("2", u.Query().Get("y"), "Unexpected query parameter y")
88+
})
89+
})
4690
}
4791

4892
// CurrentAuthorizationHeader behavior is now implicit via executeRequest using Manager.BearerToken
4993

50-
func TestExecuteRequest_SetsAuthAndCallsServer(t *testing.T) {
94+
func (s *KialiSuite) TestExecuteRequest() {
5195
// setup test server to assert path and auth header
5296
var seenAuth string
5397
var seenPath string
54-
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
98+
s.MockServer.Config().BearerToken = "token-xyz"
99+
s.MockServer.Handle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
55100
seenAuth = r.Header.Get("Authorization")
56101
seenPath = r.URL.String()
57102
_, _ = w.Write([]byte("ok"))
58103
}))
59-
defer srv.Close()
60-
61-
cfg := config.Default()
62-
cfg.SetToolsetConfig("kiali", &Config{Url: srv.URL})
63-
m := NewManager(cfg)
64-
m.BearerToken = "token-xyz"
65-
k := m.GetKiali()
66-
out, err := k.executeRequest(context.Background(), "/api/ping?q=1")
67-
if err != nil {
68-
t.Fatalf("unexpected error: %v", err)
69-
}
70-
if out != "ok" {
71-
t.Fatalf("unexpected body: %s", out)
72-
}
73-
if seenAuth != "Bearer token-xyz" {
74-
t.Fatalf("expected auth header to be set, got '%s'", seenAuth)
75-
}
76-
if seenPath != "/api/ping?q=1" {
77-
t.Fatalf("unexpected path: %s", seenPath)
78-
}
104+
105+
s.Config = test.Must(config.ReadToml([]byte(fmt.Sprintf(`
106+
[toolset_configs.kiali]
107+
url = "%s"
108+
`, s.MockServer.Config().Host))))
109+
k := NewKiali(s.Config, s.MockServer.Config())
110+
111+
out, err := k.executeRequest(s.T().Context(), "/api/ping?q=1")
112+
s.Require().NoError(err, "Expected no error executing request")
113+
s.Run("auth header set", func() {
114+
s.Equal("Bearer token-xyz", seenAuth, "Unexpected Authorization header")
115+
})
116+
s.Run("path is correct", func() {
117+
s.Equal("/api/ping?q=1", seenPath, "Unexpected path")
118+
})
119+
s.Run("response body is correct", func() {
120+
s.Equal("ok", out, "Unexpected response body")
121+
})
122+
}
123+
124+
func TestKiali(t *testing.T) {
125+
suite.Run(t, new(KialiSuite))
79126
}

pkg/kiali/manager.go

Lines changed: 0 additions & 32 deletions
This file was deleted.

pkg/kiali/manager_test.go

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)