add kiali client with authentication supports

Signed-off-by: Roland.Ma <rolandma@yunify.com>
This commit is contained in:
Roland.Ma
2021-07-08 07:10:03 +00:00
parent a897caa366
commit 85fd94b922
8 changed files with 449 additions and 76 deletions

View File

@@ -29,8 +29,6 @@ import (
"kubesphere.io/kubesphere/pkg/utils/signals"
"kubesphere.io/kubesphere/pkg/utils/term"
"kubesphere.io/kubesphere/pkg/version"
tracing "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
)
func NewAPIServerCommand() *cobra.Command {
@@ -90,8 +88,6 @@ cluster's shared state through which all other components interact.`,
func Run(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
initializeServicemeshConfig(s)
apiserver, err := s.NewAPIServer(stopCh)
if err != nil {
return err
@@ -104,15 +100,3 @@ func Run(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
return apiserver.Run(stopCh)
}
func initializeServicemeshConfig(s *options.ServerRunOptions) {
// Config jaeger query endpoint address
if s.ServiceMeshOptions != nil && len(s.ServiceMeshOptions.JaegerQueryHost) != 0 {
tracing.JaegerQueryUrl = s.ServiceMeshOptions.JaegerQueryHost
}
// Set the kiali query endpoint address
if s.ServiceMeshOptions != nil && len(s.ServiceMeshOptions.KialiQueryHost) != 0 {
tracing.KialiQueryUrl = s.ServiceMeshOptions.KialiQueryHost
}
}

View File

@@ -254,7 +254,7 @@ func (s *APIServer) installKubeSphereAPIs() {
auth.NewLoginRecorder(s.KubernetesClient.KubeSphere(),
s.InformerFactory.KubeSphereSharedInformerFactory().Iam().V1alpha2().Users().Lister()),
s.Config.AuthenticationOptions))
urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container))
urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.Config.ServiceMeshOptions, s.container, s.KubernetesClient.Kubernetes(), s.CacheClient))
urlruntime.Must(networkv1alpha2.AddToContainer(s.container, s.Config.NetworkOptions.WeaveScopeHost))
urlruntime.Must(devopsv1alpha2.AddToContainer(s.container,
s.InformerFactory.KubeSphereSharedInformerFactory(),

View File

@@ -29,5 +29,5 @@ func init() {
}
func Install(c *restful.Container) {
urlruntime.Must(v1alpha2.AddToContainer(c))
urlruntime.Must(v1alpha2.AddToContainer(nil, c, nil, nil))
}

View File

@@ -17,44 +17,67 @@ limitations under the License.
package v1alpha2
import (
"context"
"errors"
"fmt"
"io/ioutil"
"net/http"
"github.com/emicklei/go-restful"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/kiali"
"kubesphere.io/kubesphere/pkg/simple/client/servicemesh"
)
// default jaeger query api endpoint address
var JaegerQueryUrl = "http://jaeger-query.istio-system.svc:16686"
const (
KubesphereNamespace = "kubesphere-system"
KubeSphereServiceAccount = "kubesphere"
)
/*
Use Kiali API directly if config existed in configmap.
Such as:
kubectl -n kubesphere-system get cm kubesphere-config -oyaml
...
kialiQueryHost: http://kiali.istio-system:20001
...
type Handler struct {
opt *servicemesh.Options
client *kiali.Client
}
Otherwise, use the API provided by kiali code.
Announce: The API provided by kiali code will deprecated in the future.
*/
var KialiQueryUrl string
func NewHandler(o *servicemesh.Options, client kubernetes.Interface, cache cache.Interface) *Handler {
if o != nil && o.KialiQueryHost != "" {
sa, err := client.CoreV1().ServiceAccounts(KubesphereNamespace).Get(context.TODO(), KubeSphereServiceAccount, metav1.GetOptions{})
if err == nil {
secret, err := client.CoreV1().Secrets(KubesphereNamespace).Get(context.TODO(), sa.Secrets[0].Name, metav1.GetOptions{})
if err == nil {
return &Handler{
opt: o,
client: kiali.NewDefaultClient(
cache,
string(secret.Data["token"]),
o.KialiQueryHost,
),
}
}
klog.Warningf("get ServiceAccount's Secret failed %v", err)
}
klog.Warningf("get ServiceAccount failed %v", err)
}
// Handler should return Status code 400, instead of crash ks-apiserver
// when no client is defined.
return &Handler{opt: o, client: nil}
}
// Get app metrics
func getAppMetrics(request *restful.Request, response *restful.Response) {
func (h *Handler) GetAppMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
app := request.PathParameter("app")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/apps/%s/metrics?%s", KialiQueryUrl, namespace, app, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/apps/%s/metrics?%s", namespace, app, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get workload metrics
func getWorkloadMetrics(request *restful.Request, response *restful.Response) {
func (h *Handler) GetWorkloadMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
workload := request.PathParameter("workload")
@@ -62,77 +85,114 @@ func getWorkloadMetrics(request *restful.Request, response *restful.Response) {
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s&workload=%s", request.Request.URL.RawQuery, namespace, workload)
}
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/workloads/%s/metrics?%s", KialiQueryUrl, namespace, workload, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/workloads/%s/metrics?%s", namespace, workload, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get service metrics
func getServiceMetrics(request *restful.Request, response *restful.Response) {
func (h *Handler) GetServiceMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
service := request.PathParameter("service")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/services/%s/metrics?%s", KialiQueryUrl, namespace, service, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/services/%s/metrics?%s", namespace, service, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get namespace metrics
func getNamespaceMetrics(request *restful.Request, response *restful.Response) {
func (h *Handler) GetNamespaceMetrics(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/metrics?%s", KialiQueryUrl, namespace, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/metrics?%s", namespace, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get service graph for namespace
func getNamespaceGraph(request *restful.Request, response *restful.Response) {
func (h *Handler) GetNamespaceGraph(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
if len(namespace) > 0 {
request.Request.URL.RawQuery = fmt.Sprintf("%s&namespaces=%s", request.Request.URL.RawQuery, namespace)
}
url := fmt.Sprintf("%s/kiali/api/namespaces/graph?%s", KialiQueryUrl, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/graph?%s", request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get namespace health
func getNamespaceHealth(request *restful.Request, response *restful.Response) {
func (h *Handler) GetNamespaceHealth(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/health?%s", KialiQueryUrl, namespace, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/health?%s", namespace, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get workload health
func getWorkloadHealth(request *restful.Request, response *restful.Response) {
func (h *Handler) GetWorkloadHealth(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
workload := request.PathParameter("workload")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/workloads/%s/health?%s", KialiQueryUrl, namespace, workload, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/workloads/%s/health?%s", namespace, workload, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get app health
func getAppHealth(request *restful.Request, response *restful.Response) {
func (h *Handler) GetAppHealth(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
app := request.PathParameter("app")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/apps/%s/health?%s", KialiQueryUrl, namespace, app, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/apps/%s/health?%s", namespace, app, request.Request.URL.RawQuery)
h.getData(response, url)
}
// Get service health
func getServiceHealth(request *restful.Request, response *restful.Response) {
func (h *Handler) GetServiceHealth(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
service := request.PathParameter("service")
url := fmt.Sprintf("%s/kiali/api/namespaces/%s/services/%s/health?%s", KialiQueryUrl, namespace, service, request.Request.URL.RawQuery)
getData(response, url)
url := fmt.Sprintf("/kiali/api/namespaces/%s/services/%s/health?%s", namespace, service, request.Request.URL.RawQuery)
h.getData(response, url)
}
func getServiceTracing(request *restful.Request, response *restful.Response) {
func (h *Handler) GetServiceTracing(request *restful.Request, response *restful.Response) {
namespace := request.PathParameter("namespace")
service := request.PathParameter("service")
serviceName := fmt.Sprintf("%s.%s", service, namespace)
url := fmt.Sprintf("%s/api/traces?%s&service=%s", JaegerQueryUrl, request.Request.URL.RawQuery, serviceName)
getData(response, url)
url := fmt.Sprintf("%s/api/traces?%s&service=%s", h.opt.JaegerQueryHost, request.Request.URL.RawQuery, serviceName)
h.getJaegerData(response, url)
}
func getData(response *restful.Response, url string) {
func (h *Handler) getData(response *restful.Response, url string) {
if h.client == nil {
err := errors.New("kiali url is not defined")
api.HandleInternalError(response, nil, err)
return
}
resp, err := h.client.Get(url)
klog.V(4).Infof("Proxy request to %s", url)
if err != nil {
klog.Errorf("query url %s failed with err %v", url, err)
api.HandleInternalError(response, nil, err)
return
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
klog.Errorf("read response error : %v", err)
api.HandleInternalError(response, nil, err)
return
}
// need to set header for proper response
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(body)
if err != nil {
klog.Errorf("write response failed %v", err)
}
}
// TODO: to be removed with a security Jaeger client
func (h *Handler) getJaegerData(response *restful.Response, url string) {
resp, err := http.Get(url)
klog.V(4).Infof("Proxy request to %s", url)

View File

@@ -22,24 +22,29 @@ import (
"github.com/emicklei/go-restful"
restfulspec "github.com/emicklei/go-restful-openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
"kubesphere.io/kubesphere/pkg/simple/client/servicemesh"
)
const groupName = "servicemesh.kubesphere.io"
var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha2"}
func AddToContainer(c *restful.Container) error {
func AddToContainer(o *servicemesh.Options, c *restful.Container, client kubernetes.Interface, cache cache.Interface) error {
tags := []string{"ServiceMesh"}
webservice := runtime.NewWebService(GroupVersion)
h := NewHandler(o, client, cache)
// Get service metrics
// GET /namespaces/{namespace}/services/{service}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/metrics").
To(getServiceMetrics).
To(h.GetServiceMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get service metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
@@ -59,7 +64,7 @@ func AddToContainer(c *restful.Container) error {
// Get app metrics
// Get /namespaces/{namespace}/apps/{app}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/metrics").
To(getAppMetrics).
To(h.GetAppMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get app metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace")).
@@ -79,7 +84,7 @@ func AddToContainer(c *restful.Container) error {
// Get workload metrics
// Get /namespaces/{namespace}/workloads/{workload}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/metrics").
To(getWorkloadMetrics).
To(h.GetWorkloadMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get workload metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)).
@@ -99,7 +104,7 @@ func AddToContainer(c *restful.Container) error {
// Get namespace metrics
// Get /namespaces/{namespace}/metrics
webservice.Route(webservice.GET("/namespaces/{namespace}/metrics").
To(getNamespaceMetrics).
To(h.GetNamespaceMetrics).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get metrics from a specific namespace").
Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)).
@@ -118,7 +123,7 @@ func AddToContainer(c *restful.Container) error {
// Get namespace graph
// Get /namespaces/{namespace}/graph
webservice.Route(webservice.GET("/namespaces/{namespace}/graph").
To(getNamespaceGraph).
To(h.GetNamespaceGraph).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get service graph for a specific namespace").
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
@@ -133,7 +138,7 @@ func AddToContainer(c *restful.Container) error {
// Get namespace health
webservice.Route(webservice.GET("/namespaces/{namespace}/health").
To(getNamespaceHealth).
To(h.GetNamespaceHealth).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get app/service/workload health of a namespace").
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
@@ -145,7 +150,7 @@ func AddToContainer(c *restful.Container) error {
// Get workloads health
webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/health").
To(getWorkloadHealth).
To(h.GetWorkloadHealth).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get workload health").
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
@@ -156,7 +161,7 @@ func AddToContainer(c *restful.Container) error {
// Get app health
webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/health").
To(getAppHealth).
To(h.GetAppHealth).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get app health").
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
@@ -167,7 +172,7 @@ func AddToContainer(c *restful.Container) error {
// Get service health
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/health").
To(getServiceHealth).
To(h.GetServiceHealth).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("Get service health").
Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)).
@@ -178,7 +183,7 @@ func AddToContainer(c *restful.Container) error {
// Get service tracing
webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/traces").
To(getServiceTracing).
To(h.GetServiceTracing).
Doc("Get tracing of a service, should have servicemesh enabled first").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(webservice.PathParameter("namespace", "namespace of service").Required(true)).

View File

@@ -0,0 +1,174 @@
/*
Copyright 2021 KubeSphere 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 kiali
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
)
// Kiali token Response
type TokenResponse struct {
// The username for the token
Username string `json:"username"`
// The authentication token
Token string `json:"token"`
// The expired time for the token
ExpiresOn string `json:"expiresOn"`
}
// Kiali Authentication Strategy
type Strategy string
const (
AuthStrategyToken Strategy = "token"
AuthStrategyAnonymous Strategy = "anonymous"
)
const (
AuthURL = "%s/kiali/api/authenticate"
KialiTokenCacheKey = "kubesphere:kubesphere:kiali"
)
type HttpClient interface {
// Do is an interface of http client Do method,
// that sends an HTTP request and returns an HTTP response.
Do(req *http.Request) (*http.Response, error)
// PostForm is an interface of http client PostForm method,
// that issues a POST to the specified URL.
PostForm(url string, data url.Values) (resp *http.Response, err error)
}
// Kiali Client
type Client struct {
Strategy Strategy
cache cache.Interface
client HttpClient
ServiceToken string
Host string
}
// NewClient creates an instance of Kiali Client.
func NewClient(strategy Strategy,
cache cache.Interface,
client HttpClient,
serviceToken string,
host string) *Client {
return &Client{
Strategy: strategy,
cache: cache,
client: client,
ServiceToken: serviceToken,
Host: host,
}
}
// NewDefaultClient creates an instance of Kiali Client with default http settings.
func NewDefaultClient(
cache cache.Interface,
serviceToken string,
host string) *Client {
return &Client{
Strategy: AuthStrategyToken,
cache: cache,
client: &http.Client{},
ServiceToken: serviceToken,
Host: host,
}
}
// authenticate sends auth request with Kubernetes token and
// get Kiali token from the response.
func (c *Client) authenticate() (*TokenResponse, error) {
resp, err := c.client.PostForm(fmt.Sprintf(AuthURL, c.Host), url.Values{
"token": {c.ServiceToken},
})
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
token := TokenResponse{}
err = json.Unmarshal(body, &token)
if err != nil {
return nil, err
}
return &token, nil
}
// Get issues a GET to the Kiali server with the url.
func (c *Client) Get(url string) (resp *http.Response, err error) {
if req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s%s", c.Host, url), nil); err != nil {
return nil, err
} else {
if c.Strategy == AuthStrategyToken {
err := c.SetToken(req)
if err != nil {
return nil, err
}
}
resp, err := c.client.Do(req)
if err != nil {
c.clearTokenCache(err)
}
return resp, err
}
}
func (c *Client) clearTokenCache(err error) {
if c.cache != nil && err != nil {
c.cache.Del(KialiTokenCacheKey)
}
}
// SetToken gets token from the Kiali server/cache and sets Bearer token to the request header.
func (c *Client) SetToken(req *http.Request) error {
if c.cache != nil {
token, err := c.cache.Get(KialiTokenCacheKey)
if err == nil {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
return nil
}
}
token, err := c.authenticate()
if err != nil {
return err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Token))
if c.cache != nil {
c.cache.Set(KialiTokenCacheKey, token.Token, time.Hour)
}
return nil
}

View File

@@ -0,0 +1,150 @@
/*
Copyright 2021 KubeSphere 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 kiali
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"testing"
"kubesphere.io/kubesphere/pkg/simple/client/cache"
)
func TestClient_Get(t *testing.T) {
type fields struct {
Strategy Strategy
cache cache.Interface
client HttpClient
ServiceToken string
Host string
}
type args struct {
url string
}
token, _ := json.Marshal(
&TokenResponse{
Username: "test",
Token: "test",
},
)
tests := []struct {
name string
fields fields
args args
wantResp *http.Response
wantErr bool
}{
{
name: "Anonymous",
fields: fields{
Strategy: AuthStrategyAnonymous,
cache: nil,
client: &MockClient{
requestResult: "fake",
},
ServiceToken: "token",
Host: "http://kiali.istio-system.svc",
},
args: args{url: "http://kiali.istio-system.svc"},
wantResp: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte("fake"))),
},
wantErr: false,
},
{
name: "Token",
fields: fields{
Strategy: AuthStrategyToken,
cache: nil,
client: &MockClient{
tokenResult: token,
requestResult: "fake",
},
ServiceToken: "token",
Host: "http://kiali.istio-system.svc",
},
args: args{url: "http://kiali.istio-system.svc"},
wantResp: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte("fake"))),
},
wantErr: false,
},
{
name: "Token",
fields: fields{
Strategy: AuthStrategyToken,
cache: cache.NewSimpleCache(),
client: &MockClient{
tokenResult: token,
requestResult: "fake",
},
ServiceToken: "token",
Host: "http://kiali.istio-system.svc",
},
args: args{url: "http://kiali.istio-system.svc"},
wantResp: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte("fake"))),
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := NewClient(
tt.fields.Strategy,
tt.fields.cache,
tt.fields.client,
tt.fields.ServiceToken,
tt.fields.Host,
)
gotResp, err := c.Get(tt.args.url)
if (err != nil) != tt.wantErr {
t.Errorf("Client.Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotResp, tt.wantResp) {
t.Errorf("Client.Get() = %v, want %v", gotResp, tt.wantResp)
}
})
}
}
type MockClient struct {
tokenResult []byte
requestResult string
}
func (c *MockClient) Do(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader([]byte(c.requestResult))),
}, nil
}
func (c *MockClient) PostForm(url string, data url.Values) (resp *http.Response, err error) {
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewReader(c.tokenResult)),
}, nil
}

View File

@@ -133,7 +133,7 @@ func generateSwaggerJson() []byte {
urlruntime.Must(resourcesv1alpha3.AddToContainer(container, informerFactory, nil))
urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil))
urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil, nil))
urlruntime.Must(metricsv1alpha2.AddToContainer(container))
urlruntime.Must(metricsv1alpha2.AddToContainer(nil, container, clientsets.Kubernetes(), nil))
urlruntime.Must(networkv1alpha2.AddToContainer(container, ""))
alertingOptions := &alerting.Options{}
alertingClient, _ := alerting.NewRuleClient(alertingOptions)