@@ -17,7 +17,6 @@ limitations under the License.
1717package http
1818
1919import (
20- "bytes"
2120 "context"
2221 "encoding/base64"
2322 "encoding/json"
@@ -42,6 +41,7 @@ import (
4241 "github.com/kube-bind/kube-bind/backend/kubernetes"
4342 "github.com/kube-bind/kube-bind/backend/kubernetes/resources"
4443 "github.com/kube-bind/kube-bind/backend/session"
44+ "github.com/kube-bind/kube-bind/backend/spaserver"
4545 "github.com/kube-bind/kube-bind/backend/template"
4646 bindversion "github.com/kube-bind/kube-bind/pkg/version"
4747 kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
@@ -73,6 +73,8 @@ type handler struct {
7373
7474 client * http.Client
7575 kubeManager * kubernetes.Manager
76+
77+ frontend string
7678}
7779
7880func NewHandler (
@@ -82,6 +84,7 @@ func NewHandler(
8284 schemaSource string ,
8385 scope kubebindv1alpha2.InformerScope ,
8486 mgr * kubernetes.Manager ,
87+ frontend string ,
8588) (* handler , error ) {
8689 return & handler {
8790 oidc : provider ,
@@ -90,6 +93,7 @@ func NewHandler(
9093 providerPrettyName : providerPrettyName ,
9194 testingAutoSelect : testingAutoSelect ,
9295 schemaSource : schemaSource ,
96+ frontend : frontend ,
9397 scope : scope ,
9498 client : http .DefaultClient ,
9599 kubeManager : mgr ,
@@ -99,7 +103,7 @@ func NewHandler(
99103}
100104
101105func (h * handler ) AddRoutes (mux * mux.Router ) {
102- // Server contains double routes for when backend is multi-cluster aware or single cluster.
106+ // API routes - Server contains double routes for when backend is multi-cluster aware or single cluster.
103107 // When called multi-cluster aware route in single cluster mode, it will ignore cluster parameter.
104108 mux .HandleFunc ("/api/clusters/{cluster}/exports" , h .handleServiceExport ).Methods ("GET" )
105109 mux .HandleFunc ("/api/exports" , h .handleServiceExport ).Methods ("GET" )
@@ -115,6 +119,18 @@ func (h *handler) AddRoutes(mux *mux.Router) {
115119
116120 mux .HandleFunc ("/api/callback" , h .handleCallback ).Methods ("GET" )
117121 mux .HandleFunc ("/api/healthz" , h .handleHealthz ).Methods ("GET" )
122+
123+ if strings .HasPrefix (h .frontend , "http://" ) {
124+ spaserver , err := spaserver .NewSPAReverseProxyServer (h .frontend )
125+ if err != nil {
126+ panic (fmt .Sprintf ("failed to create SPA reverse proxy server: %v" , err )) // Development only.
127+ }
128+ mux .PathPrefix ("/" ).Handler (spaserver )
129+ } else {
130+ fileSystem := http .Dir (h .frontend )
131+ mux .PathPrefix ("/" ).Handler (spaserver .NewSPAFileServer (fileSystem ))
132+ }
133+
118134}
119135
120136func (h * handler ) handleHealthz (w http.ResponseWriter , r * http.Request ) {
@@ -148,7 +164,7 @@ func (h *handler) handleServiceExport(w http.ResponseWriter, r *http.Request) {
148164 Kind : "BindingProvider" ,
149165 },
150166 Version : ver ,
151- ProviderPrettyName : "example- backend" ,
167+ ProviderPrettyName : "backend" ,
152168 AuthenticationMethods : []kubebindv1alpha2.AuthenticationMethod {
153169 {
154170 Method : "OAuth2CodeGrant" ,
@@ -293,9 +309,9 @@ func (h *handler) handleCallback(w http.ResponseWriter, r *http.Request) {
293309
294310 http .SetCookie (w , session .MakeCookie (r , cookieName , encoded , secure , 1 * time .Hour ))
295311 if authCode .ProviderClusterID == "" {
296- http .Redirect (w , r , "/api/ resources?s=" + cookieName , http .StatusFound )
312+ http .Redirect (w , r , "/resources?s=" + cookieName , http .StatusFound )
297313 } else {
298- http .Redirect (w , r , "/api/ clusters/" + authCode .ProviderClusterID + "/resources?s=" + cookieName , http .StatusFound )
314+ http .Redirect (w , r , "/clusters/" + authCode .ProviderClusterID + "/resources?s=" + cookieName , http .StatusFound )
299315 }
300316}
301317
@@ -379,35 +395,31 @@ func (h *handler) handleResources(w http.ResponseWriter, r *http.Request) {
379395 return
380396 }
381397
382- var result [] UISchema
398+ result := kubebindv1alpha2. BindableResourcesResponse {}
383399 for _ , item := range exportedSchemas {
384- result = append (result , UISchema {
385- Name : item .GetName (),
386- Kind : item .Spec .Names .Kind ,
387- Scope : string (item .Spec .Scope ),
388- Version : item .Spec .Versions [0 ].Name ,
389- Group : item .Spec .Group ,
400+
401+ result .Resources = append (result .Resources , kubebindv1alpha2.BindableResource {
402+ Name : item .GetName (),
403+ Kind : item .Spec .Names .Kind ,
404+ Scope : string (item .Spec .Scope ),
405+ APIVersion : item .Spec .Versions [0 ].Name ,
406+ Group : item .Spec .Group ,
390407 // Important: This MUST be used as UI button class in the url, so tests can 'click it' based on it.
391408 Resource : item .Spec .Names .Plural ,
392409 SessionID : sessionID ,
393410 })
394411 }
395412
396- bs := bytes.Buffer {}
397- if err := resourcesTemplate .Execute (& bs , struct {
398- Cluster string
399- Schemas []UISchema
400- }{
401- Cluster : providerCluster ,
402- Schemas : result ,
403- }); err != nil {
404- logger .Error (err , "failed to execute template" )
413+ bs , err := json .Marshal (& result )
414+ if err != nil {
415+ logger .Error (err , "failed to marshal resources" )
405416 http .Error (w , "internal error" , http .StatusInternalServerError )
406417 return
407418 }
408419
409- w .Header ().Set ("Content-Type" , "text/html; charset=utf-8" )
410- w .Write (bs .Bytes ()) //nolint:errcheck
420+ w .Header ().Set ("Content-Type" , "application/json" )
421+ w .Write (bs ) //nolint:errcheck
422+
411423}
412424
413425func (h * handler ) handleBind (w http.ResponseWriter , r * http.Request ) {
0 commit comments