mirror of
https://github.com/rancher/steve.git
synced 2025-09-22 20:09:34 +00:00
Add functions ServeAPIUI apiUIPath for api ui assets (#806)
This commit is contained in:
committed by
GitHub
parent
13d5ad3ccb
commit
0c6dd58fc5
2
go.mod
2
go.mod
@@ -20,7 +20,7 @@ require (
|
|||||||
github.com/pborman/uuid v1.2.1
|
github.com/pborman/uuid v1.2.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/rancher/apiserver v0.7.2
|
github.com/rancher/apiserver v0.7.3
|
||||||
github.com/rancher/dynamiclistener v0.7.0
|
github.com/rancher/dynamiclistener v0.7.0
|
||||||
github.com/rancher/kubernetes-provider-detector v0.1.5
|
github.com/rancher/kubernetes-provider-detector v0.1.5
|
||||||
github.com/rancher/lasso v0.2.3
|
github.com/rancher/lasso v0.2.3
|
||||||
|
4
go.sum
4
go.sum
@@ -214,8 +214,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
|
|||||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rancher/apiserver v0.7.2 h1:mDgVHgDF0DJ2AmN6KGzdlk1ueAJJJGYOrJhXG+1LNn8=
|
github.com/rancher/apiserver v0.7.3 h1:a9yibIRiZe2kQ5X+x5cXgajff8S9j3sTu7+kxT6g4hs=
|
||||||
github.com/rancher/apiserver v0.7.2/go.mod h1:9b/n58YT7S8bMFEyr1v7xzL72qwZKQQJK2Ir6lMT8Yk=
|
github.com/rancher/apiserver v0.7.3/go.mod h1:9b/n58YT7S8bMFEyr1v7xzL72qwZKQQJK2Ir6lMT8Yk=
|
||||||
github.com/rancher/dynamiclistener v0.7.0 h1:+jyfZ4lVamc1UbKWo8V8dhSPtCgRZYaY8nm7wiHeko4=
|
github.com/rancher/dynamiclistener v0.7.0 h1:+jyfZ4lVamc1UbKWo8V8dhSPtCgRZYaY8nm7wiHeko4=
|
||||||
github.com/rancher/dynamiclistener v0.7.0/go.mod h1:Q2YA42xp7Xc69JiSlJ8GpvLvze261T0iQ/TP4RdMCYk=
|
github.com/rancher/dynamiclistener v0.7.0/go.mod h1:Q2YA42xp7Xc69JiSlJ8GpvLvze261T0iQ/TP4RdMCYk=
|
||||||
github.com/rancher/kubernetes-provider-detector v0.1.5 h1:hWRAsWuJOemzGjz/XrbTlM7QmfO4OedvFE3QwXiH60I=
|
github.com/rancher/kubernetes-provider-detector v0.1.5 h1:hWRAsWuJOemzGjz/XrbTlM7QmfO4OedvFE3QwXiH60I=
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/rancher/apiserver/pkg/middleware"
|
"github.com/rancher/apiserver/pkg/middleware"
|
||||||
@@ -20,12 +22,13 @@ type StringSetting func() string
|
|||||||
type BoolSetting func() bool
|
type BoolSetting func() bool
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
pathSetting func() string
|
pathSetting func() string
|
||||||
indexSetting func() string
|
indexSetting func() string
|
||||||
releaseSetting func() bool
|
releaseSetting func() bool
|
||||||
offlineSetting func() string
|
offlineSetting func() string
|
||||||
middleware func(http.Handler) http.Handler
|
apiUIVersionSetting func() string
|
||||||
indexMiddleware func(http.Handler) http.Handler
|
middleware func(http.Handler) http.Handler
|
||||||
|
indexMiddleware func(http.Handler) http.Handler
|
||||||
|
|
||||||
downloadOnce sync.Once
|
downloadOnce sync.Once
|
||||||
downloadSuccess bool
|
downloadSuccess bool
|
||||||
@@ -40,6 +43,8 @@ type Options struct {
|
|||||||
Offline StringSetting
|
Offline StringSetting
|
||||||
// Whether or not is it release, if true UI will run offline if set to dynamic
|
// Whether or not is it release, if true UI will run offline if set to dynamic
|
||||||
ReleaseSetting BoolSetting
|
ReleaseSetting BoolSetting
|
||||||
|
// The version of API UI to use
|
||||||
|
APIUIVersionSetting StringSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUIHandler(opts *Options) *Handler {
|
func NewUIHandler(opts *Options) *Handler {
|
||||||
@@ -48,10 +53,11 @@ func NewUIHandler(opts *Options) *Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h := &Handler{
|
h := &Handler{
|
||||||
indexSetting: opts.Index,
|
indexSetting: opts.Index,
|
||||||
offlineSetting: opts.Offline,
|
offlineSetting: opts.Offline,
|
||||||
pathSetting: opts.Path,
|
pathSetting: opts.Path,
|
||||||
releaseSetting: opts.ReleaseSetting,
|
releaseSetting: opts.ReleaseSetting,
|
||||||
|
apiUIVersionSetting: opts.APIUIVersionSetting,
|
||||||
middleware: middleware.Chain{
|
middleware: middleware.Chain{
|
||||||
middleware.Gzip,
|
middleware.Gzip,
|
||||||
middleware.FrameOptions,
|
middleware.FrameOptions,
|
||||||
@@ -94,7 +100,7 @@ func NewUIHandler(opts *Options) *Handler {
|
|||||||
|
|
||||||
func (u *Handler) canDownload(url string) bool {
|
func (u *Handler) canDownload(url string) bool {
|
||||||
u.downloadOnce.Do(func() {
|
u.downloadOnce.Do(func() {
|
||||||
if err := serveIndex(ioutil.Discard, url); err == nil {
|
if err := serveRemote(ioutil.Discard, url); err == nil {
|
||||||
u.downloadSuccess = true
|
u.downloadSuccess = true
|
||||||
} else {
|
} else {
|
||||||
logrus.Errorf("Failed to download %s, falling back to packaged UI", url)
|
logrus.Errorf("Failed to download %s, falling back to packaged UI", url)
|
||||||
@@ -103,7 +109,7 @@ func (u *Handler) canDownload(url string) bool {
|
|||||||
return u.downloadSuccess
|
return u.downloadSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Handler) path() (path string, isURL bool) {
|
func (u *Handler) indexPath() (path string, isURL bool) {
|
||||||
switch u.offlineSetting() {
|
switch u.offlineSetting() {
|
||||||
case "dynamic":
|
case "dynamic":
|
||||||
if u.releaseSetting() {
|
if u.releaseSetting() {
|
||||||
@@ -120,6 +126,46 @@ func (u *Handler) path() (path string, isURL bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *Handler) apiUIPath() (string, bool) {
|
||||||
|
version := u.apiUIVersionSetting()
|
||||||
|
remotePath := "https://releases.rancher.com/api-ui/"
|
||||||
|
|
||||||
|
switch u.offlineSetting() {
|
||||||
|
case "dynamic":
|
||||||
|
if u.releaseSetting() {
|
||||||
|
return filepath.Join(u.pathSetting(), "api-ui"), false
|
||||||
|
}
|
||||||
|
if u.canDownload(fmt.Sprintf("%s/%s/%s", remotePath, version, "ui.min.js")) {
|
||||||
|
return remotePath, true
|
||||||
|
}
|
||||||
|
return filepath.Join(u.pathSetting(), "api-ui"), false
|
||||||
|
case "true":
|
||||||
|
return filepath.Join(u.pathSetting(), "api-ui"), false
|
||||||
|
default:
|
||||||
|
return remotePath, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Handler) ServeAPIUI() http.Handler {
|
||||||
|
return u.middleware(http.StripPrefix("/api-ui/",
|
||||||
|
http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
base, isURL := u.apiUIPath()
|
||||||
|
if isURL {
|
||||||
|
remoteURL := base + req.URL.Path
|
||||||
|
if err := serveRemote(rw, remoteURL); err != nil {
|
||||||
|
logrus.Errorf("failed to fetch asset from %s: %v", remoteURL, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parts := strings.SplitN(req.URL.Path, "/", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
http.ServeFile(rw, req, filepath.Join(base, parts[1]))
|
||||||
|
} else {
|
||||||
|
http.NotFound(rw, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Handler) ServeAsset() http.Handler {
|
func (u *Handler) ServeAsset() http.Handler {
|
||||||
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
return u.middleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
http.FileServer(http.Dir(u.pathSetting())).ServeHTTP(rw, req)
|
http.FileServer(http.Dir(u.pathSetting())).ServeHTTP(rw, req)
|
||||||
@@ -145,8 +191,8 @@ func (u *Handler) IndexFileOnNotFound() http.Handler {
|
|||||||
|
|
||||||
func (u *Handler) IndexFile() http.Handler {
|
func (u *Handler) IndexFile() http.Handler {
|
||||||
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
return u.indexMiddleware(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
if path, isURL := u.path(); isURL {
|
if path, isURL := u.indexPath(); isURL {
|
||||||
err := serveIndex(rw, path)
|
err := serveRemote(rw, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("failed to download %s: %v", path, err)
|
logrus.Errorf("failed to download %s: %v", path, err)
|
||||||
}
|
}
|
||||||
@@ -156,7 +202,7 @@ func (u *Handler) IndexFile() http.Handler {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveIndex(resp io.Writer, url string) error {
|
func serveRemote(resp io.Writer, url string) error {
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
@@ -168,6 +214,15 @@ func serveIndex(resp io.Writer, url string) error {
|
|||||||
}
|
}
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
if w, ok := resp.(http.ResponseWriter); ok {
|
||||||
|
for k, v := range r.Header {
|
||||||
|
for _, vv := range v {
|
||||||
|
w.Header().Add(k, vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.WriteHeader(r.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = io.Copy(resp, r.Body)
|
_, err = io.Copy(resp, r.Body)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user