Skip to content

Commit 0c6dd58

Browse files
authored
Add functions ServeAPIUI apiUIPath for api ui assets (#806)
1 parent 13d5ad3 commit 0c6dd58

File tree

3 files changed

+73
-18
lines changed

3 files changed

+73
-18
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ require (
2020
github.com/pborman/uuid v1.2.1
2121
github.com/pkg/errors v0.9.1
2222
github.com/prometheus/client_golang v1.22.0
23-
github.com/rancher/apiserver v0.7.2
23+
github.com/rancher/apiserver v0.7.3
2424
github.com/rancher/dynamiclistener v0.7.0
2525
github.com/rancher/kubernetes-provider-detector v0.1.5
2626
github.com/rancher/lasso v0.2.3

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
214214
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
215215
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
216216
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
217-
github.com/rancher/apiserver v0.7.2 h1:mDgVHgDF0DJ2AmN6KGzdlk1ueAJJJGYOrJhXG+1LNn8=
218-
github.com/rancher/apiserver v0.7.2/go.mod h1:9b/n58YT7S8bMFEyr1v7xzL72qwZKQQJK2Ir6lMT8Yk=
217+
github.com/rancher/apiserver v0.7.3 h1:a9yibIRiZe2kQ5X+x5cXgajff8S9j3sTu7+kxT6g4hs=
218+
github.com/rancher/apiserver v0.7.3/go.mod h1:9b/n58YT7S8bMFEyr1v7xzL72qwZKQQJK2Ir6lMT8Yk=
219219
github.com/rancher/dynamiclistener v0.7.0 h1:+jyfZ4lVamc1UbKWo8V8dhSPtCgRZYaY8nm7wiHeko4=
220220
github.com/rancher/dynamiclistener v0.7.0/go.mod h1:Q2YA42xp7Xc69JiSlJ8GpvLvze261T0iQ/TP4RdMCYk=
221221
github.com/rancher/kubernetes-provider-detector v0.1.5 h1:hWRAsWuJOemzGjz/XrbTlM7QmfO4OedvFE3QwXiH60I=

pkg/ui/handler.go

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package ui
22

33
import (
4+
"fmt"
45
"io"
56
"io/ioutil"
67
"net/http"
78
"os"
89
"path/filepath"
10+
"strings"
911
"sync"
1012

1113
"github.com/rancher/apiserver/pkg/middleware"
@@ -20,12 +22,13 @@ type StringSetting func() string
2022
type BoolSetting func() bool
2123

2224
type Handler struct {
23-
pathSetting func() string
24-
indexSetting func() string
25-
releaseSetting func() bool
26-
offlineSetting func() string
27-
middleware func(http.Handler) http.Handler
28-
indexMiddleware func(http.Handler) http.Handler
25+
pathSetting func() string
26+
indexSetting func() string
27+
releaseSetting func() bool
28+
offlineSetting func() string
29+
apiUIVersionSetting func() string
30+
middleware func(http.Handler) http.Handler
31+
indexMiddleware func(http.Handler) http.Handler
2932

3033
downloadOnce sync.Once
3134
downloadSuccess bool
@@ -40,6 +43,8 @@ type Options struct {
4043
Offline StringSetting
4144
// Whether or not is it release, if true UI will run offline if set to dynamic
4245
ReleaseSetting BoolSetting
46+
// The version of API UI to use
47+
APIUIVersionSetting StringSetting
4348
}
4449

4550
func NewUIHandler(opts *Options) *Handler {
@@ -48,10 +53,11 @@ func NewUIHandler(opts *Options) *Handler {
4853
}
4954

5055
h := &Handler{
51-
indexSetting: opts.Index,
52-
offlineSetting: opts.Offline,
53-
pathSetting: opts.Path,
54-
releaseSetting: opts.ReleaseSetting,
56+
indexSetting: opts.Index,
57+
offlineSetting: opts.Offline,
58+
pathSetting: opts.Path,
59+
releaseSetting: opts.ReleaseSetting,
60+
apiUIVersionSetting: opts.APIUIVersionSetting,
5561
middleware: middleware.Chain{
5662
middleware.Gzip,
5763
middleware.FrameOptions,
@@ -94,7 +100,7 @@ func NewUIHandler(opts *Options) *Handler {
94100

95101
func (u *Handler) canDownload(url string) bool {
96102
u.downloadOnce.Do(func() {
97-
if err := serveIndex(ioutil.Discard, url); err == nil {
103+
if err := serveRemote(ioutil.Discard, url); err == nil {
98104
u.downloadSuccess = true
99105
} else {
100106
logrus.Errorf("Failed to download %s, falling back to packaged UI", url)
@@ -103,7 +109,7 @@ func (u *Handler) canDownload(url string) bool {
103109
return u.downloadSuccess
104110
}
105111

106-
func (u *Handler) path() (path string, isURL bool) {
112+
func (u *Handler) indexPath() (path string, isURL bool) {
107113
switch u.offlineSetting() {
108114
case "dynamic":
109115
if u.releaseSetting() {
@@ -120,6 +126,46 @@ func (u *Handler) path() (path string, isURL bool) {
120126
}
121127
}
122128

129+
func (u *Handler) apiUIPath() (string, bool) {
130+
version := u.apiUIVersionSetting()
131+
remotePath := "https://releases.rancher.com/api-ui/"
132+
133+
switch u.offlineSetting() {
134+
case "dynamic":
135+
if u.releaseSetting() {
136+
return filepath.Join(u.pathSetting(), "api-ui"), false
137+
}
138+
if u.canDownload(fmt.Sprintf("%s/%s/%s", remotePath, version, "ui.min.js")) {
139+
return remotePath, true
140+
}
141+
return filepath.Join(u.pathSetting(), "api-ui"), false
142+
case "true":
143+
return filepath.Join(u.pathSetting(), "api-ui"), false
144+
default:
145+
return remotePath, true
146+
}
147+
}
148+
149+
func (u *Handler) ServeAPIUI() http.Handler {
150+
return u.middleware(http.StripPrefix("/api-ui/",
151+
http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
152+
base, isURL := u.apiUIPath()
153+
if isURL {
154+
remoteURL := base + req.URL.Path
155+
if err := serveRemote(rw, remoteURL); err != nil {
156+
logrus.Errorf("failed to fetch asset from %s: %v", remoteURL, err)
157+
}
158+
} else {
159+
parts := strings.SplitN(req.URL.Path, "/", 2)
160+
if len(parts) == 2 {
161+
http.ServeFile(rw, req, filepath.Join(base, parts[1]))
162+
} else {
163+
http.NotFound(rw, req)
164+
}
165+
}
166+
})))
167+
}
168+
123169
func (u *Handler) ServeAsset() http.Handler {
124170
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
125171
http.FileServer(http.Dir(u.pathSetting())).ServeHTTP(rw, req)
@@ -145,8 +191,8 @@ func (u *Handler) IndexFileOnNotFound() http.Handler {
145191

146192
func (u *Handler) IndexFile() http.Handler {
147193
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
148-
if path, isURL := u.path(); isURL {
149-
err := serveIndex(rw, path)
194+
if path, isURL := u.indexPath(); isURL {
195+
err := serveRemote(rw, path)
150196
if err != nil {
151197
logrus.Errorf("failed to download %s: %v", path, err)
152198
}
@@ -156,7 +202,7 @@ func (u *Handler) IndexFile() http.Handler {
156202
}))
157203
}
158204

159-
func serveIndex(resp io.Writer, url string) error {
205+
func serveRemote(resp io.Writer, url string) error {
160206
client := &http.Client{
161207
Transport: &http.Transport{
162208
Proxy: http.ProxyFromEnvironment,
@@ -168,6 +214,15 @@ func serveIndex(resp io.Writer, url string) error {
168214
}
169215
defer r.Body.Close()
170216

217+
if w, ok := resp.(http.ResponseWriter); ok {
218+
for k, v := range r.Header {
219+
for _, vv := range v {
220+
w.Header().Add(k, vv)
221+
}
222+
}
223+
w.WriteHeader(r.StatusCode)
224+
}
225+
171226
_, err = io.Copy(resp, r.Body)
172227
return err
173228
}

0 commit comments

Comments
 (0)