diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 3e2d0cf9098c7d02794bbf44f849f1d7b2ed5b81..eca2dc63c2dd451ad7544409b59fdb11702a872a 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -30,6 +30,7 @@ import ( "kubesphere.io/kubesphere/pkg/apiserver/filters" "kubesphere.io/kubesphere/pkg/apiserver/request" "kubesphere.io/kubesphere/pkg/informers" + alertingv1 "kubesphere.io/kubesphere/pkg/kapis/alerting/v1" clusterkapisv1alpha1 "kubesphere.io/kubesphere/pkg/kapis/cluster/v1alpha1" configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2" devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2" @@ -37,6 +38,7 @@ import ( loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2" monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3" networkv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/network/v1alpha2" + notificationv1 "kubesphere.io/kubesphere/pkg/kapis/notification/v1" "kubesphere.io/kubesphere/pkg/kapis/oauth" openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1" operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2" @@ -174,6 +176,8 @@ func (s *APIServer) installKubeSphereAPIs() { s.SonarClient, s.KubernetesClient.KubeSphere(), s.S3Client)) + urlruntime.Must(notificationv1.AddToContainer(s.container, s.Config.NotificationOptions.Endpoint)) + urlruntime.Must(alertingv1.AddToContainer(s.container, s.Config.AlertingOptions.Endpoint)) } func (s *APIServer) Run(stopCh <-chan struct{}) (err error) { diff --git a/pkg/apiserver/config/config_test.go b/pkg/apiserver/config/config_test.go index 5bbc1f02826ba720a4abeb0b70be37cfdb5da77b..49d4844cb148624605bde110df2de565ffbe851c 100644 --- a/pkg/apiserver/config/config_test.go +++ b/pkg/apiserver/config/config_test.go @@ -95,7 +95,7 @@ func newTestConfig() (*Config, error) { Version: "6", }, AlertingOptions: &alerting.Options{ - Endpoint: "http://alerting.kubesphere-alerting-system.svc:9200", + Endpoint: "http://alerting-client-server.kubesphere-alerting-system.svc:9200/api", }, NotificationOptions: ¬ification.Options{ Endpoint: "http://notification.kubesphere-alerting-system.svc:9200", diff --git a/pkg/kapis/alerting/v1/register.go b/pkg/kapis/alerting/v1/register.go new file mode 100644 index 0000000000000000000000000000000000000000..7067966bba9e025dad66a6531881a65e23b233f2 --- /dev/null +++ b/pkg/kapis/alerting/v1/register.go @@ -0,0 +1,18 @@ +package v1 + +import ( + "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/runtime/schema" + "kubesphere.io/kubesphere/pkg/kapis/generic" +) + +var GroupVersion = schema.GroupVersion{Group: "alerting.kubesphere.io", Version: "v1"} + +func AddToContainer(container *restful.Container, endpoint string) error { + proxy, err := generic.NewGenericProxy(endpoint, GroupVersion.Group, GroupVersion.Version) + if err != nil { + return nil + } + + return proxy.AddToContainer(container) +} diff --git a/pkg/kapis/generic/generic.go b/pkg/kapis/generic/generic.go new file mode 100644 index 0000000000000000000000000000000000000000..9a9bf2119dffb9ef0fd6c384c2e18bdcc1d1dbf0 --- /dev/null +++ b/pkg/kapis/generic/generic.go @@ -0,0 +1,96 @@ +package generic + +import ( + "fmt" + "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/proxy" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/runtime" + "net/http" + "net/url" + "strings" +) + +// genericProxy is a simple proxy for external service. +type genericProxy struct { + // proxy service endpoint + Endpoint *url.URL + + // api group name exposed to clients + GroupName string + + // api version + Version string +} + +func NewGenericProxy(endpoint string, groupName string, version string) (*genericProxy, error) { + parse, err := url.Parse(endpoint) + if err != nil { + return nil, err + } + + // trim path suffix slash + parse.Path = strings.Trim(parse.Path, "/") + + return &genericProxy{ + Endpoint: parse, + GroupName: groupName, + Version: version, + }, nil +} + +func (g *genericProxy) AddToContainer(container *restful.Container) error { + webservice := runtime.NewWebService(schema.GroupVersion{ + Group: g.GroupName, + Version: g.Version, + }) + + webservice.Route(webservice.GET("/{path:*}"). + To(g.handler). + Returns(http.StatusOK, api.StatusOK, nil)) + + webservice.Route(webservice.PUT("/{path:*}"). + To(g.handler). + Returns(http.StatusOK, api.StatusOK, nil)) + + webservice.Route(webservice.POST("/{path:*}"). + To(g.handler). + Returns(http.StatusOK, api.StatusOK, nil)) + + webservice.Route(webservice.DELETE("/{path:*}"). + To(g.handler). + Returns(http.StatusOK, api.StatusOK, nil)) + + container.Add(webservice) + return nil + +} + +func (g *genericProxy) handler(request *restful.Request, response *restful.Response) { + u := g.makeURL(request) + + httpProxy := proxy.NewUpgradeAwareHandler(u, http.DefaultTransport, false, false, &errorResponder{}) + httpProxy.ServeHTTP(response, request.Request) +} + +func (g *genericProxy) makeURL(request *restful.Request) *url.URL { + u := *(request.Request.URL) + u.Host = g.Endpoint.Host + u.Scheme = g.Endpoint.Scheme + u.Path = strings.Replace(request.Request.URL.Path, fmt.Sprintf("/kapis/%s", g.GroupName), "", 1) + + // prepend path from endpoint + if len(g.Endpoint.Path) != 0 { + u.Path = fmt.Sprintf("/%s%s", g.Endpoint.Path, u.Path) + } + + return &u +} + +type errorResponder struct{} + +func (e *errorResponder) Error(w http.ResponseWriter, req *http.Request, err error) { + klog.Error(err) +} diff --git a/pkg/kapis/generic/generic_test.go b/pkg/kapis/generic/generic_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1fa921c9b47c298cf86ebe7c387e3172772aa962 --- /dev/null +++ b/pkg/kapis/generic/generic_test.go @@ -0,0 +1,60 @@ +package generic + +import ( + "github.com/emicklei/go-restful" + "github.com/google/go-cmp/cmp" + "net/http/httptest" + "net/url" + "testing" +) + +var group = "test.kubesphere.io" +var version = "v1" +var scheme = "http" + +func TestNewGenericProxy(t *testing.T) { + var testCases = []struct { + description string + endpoint string + query string + expected *url.URL + }{ + { + description: "Endpoint with path", + endpoint: "http://awesome.kubesphere-system.svc:8080/api", + query: "/kapis/test.kubesphere.io/v1/foo/bar?id=1&time=whatever", + expected: &url.URL{ + Scheme: scheme, + Host: "awesome.kubesphere-system.svc:8080", + Path: "/api/v1/foo/bar", + RawQuery: "id=1&time=whatever", + }, + }, + { + description: "Endpoint without path", + endpoint: "http://awesome.kubesphere-system.svc:8080", + query: "/kapis/test.kubesphere.io/v1/foo/bar?id=1&time=whatever", + expected: &url.URL{ + Scheme: scheme, + Host: "awesome.kubesphere-system.svc:8080", + Path: "/v1/foo/bar", + RawQuery: "id=1&time=whatever", + }, + }, + } + + for _, testCase := range testCases { + proxy, err := NewGenericProxy(testCase.endpoint, group, version) + if err != nil { + t.Error(err) + } + + t.Run(testCase.description, func(t *testing.T) { + request := httptest.NewRequest("GET", testCase.query, nil) + u := proxy.makeURL(restful.NewRequest(request)) + if diff := cmp.Diff(u, testCase.expected); len(diff) != 0 { + t.Errorf("%T differ (-got, +want): %s", testCase.expected, diff) + } + }) + } +} diff --git a/pkg/kapis/notification/v1/register.go b/pkg/kapis/notification/v1/register.go new file mode 100644 index 0000000000000000000000000000000000000000..e7219ead5fe5383ad13728d613d722e21f302f83 --- /dev/null +++ b/pkg/kapis/notification/v1/register.go @@ -0,0 +1,19 @@ +package v1 + +import ( + "github.com/emicklei/go-restful" + "k8s.io/apimachinery/pkg/runtime/schema" + "kubesphere.io/kubesphere/pkg/kapis/generic" +) + +var GroupVersion = schema.GroupVersion{Group: "notification.kubesphere.io", Version: "v1"} + +func AddToContainer(container *restful.Container, endpoint string) error { + + proxy, err := generic.NewGenericProxy(endpoint, GroupVersion.Group, GroupVersion.Version) + if err != nil { + return err + } + + return proxy.AddToContainer(container) +}