mirror of
https://github.com/cnrancher/kube-explorer.git
synced 2025-09-02 06:55:01 +00:00
Compare commits
13 Commits
v0.5.0-rc4
...
v0.4.2-rc1
Author | SHA1 | Date | |
---|---|---|---|
|
18027bbaeb | ||
|
99c03af96e | ||
|
618cd9abfb | ||
|
9c5a29c9cc | ||
|
2c0afb3776 | ||
|
ca5f23170f | ||
|
24a7324f92 | ||
|
71ad854ab1 | ||
|
67923822f5 | ||
|
1540341550 | ||
|
a5e53f2b17 | ||
|
8f069c3b38 | ||
|
568eda3e52 |
2
.github/workflows/pr.yaml
vendored
2
.github/workflows/pr.yaml
vendored
@@ -16,6 +16,4 @@ jobs:
|
||||
- name: Commitsar check
|
||||
uses: aevea/commitsar@v0.20.2
|
||||
- name: Build to test
|
||||
env:
|
||||
SKIP_COMPRESS: "true"
|
||||
run: make ci
|
||||
|
92
.github/workflows/push.yaml
vendored
92
.github/workflows/push.yaml
vendored
@@ -4,8 +4,12 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "release/v*"
|
||||
tags:
|
||||
- 'v*.*.*' # Matches any tag that starts with 'v' and follows semantic versioning
|
||||
- "v*.*.*" # Matches any tag that starts with 'v' and follows semantic versioning
|
||||
|
||||
env:
|
||||
ALIYUN_REGISTRY: ${{ vars.ALIYUN_REGISTRY || '' }}
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
@@ -15,67 +19,73 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: CI
|
||||
env:
|
||||
SKIP_PACKAGE: "true"
|
||||
run: make ci
|
||||
- name: Prepare for packaging image
|
||||
run: cp dist/* package/
|
||||
# aliyun image to test the docker build is ok
|
||||
- name: Login to Aliyun ACR
|
||||
if: ${{ vars.ALIYUN_REGISTRY != '' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.cn-shenzhen.aliyuncs.com
|
||||
registry: ${{ env.ALIYUN_REGISTRY }}
|
||||
username: ${{ secrets.ACR_USERNAME }}
|
||||
password: ${{ secrets.ACR_TOKEN }}
|
||||
if: ${{ vars.ALIYUN == 'true' }}
|
||||
- name: Aliyun image docker meta
|
||||
if: ${{ vars.ALIYUN_REGISTRY != '' }}
|
||||
id: aliyun-meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.ALIYUN_REGISTRY }}/${{ vars.REPO || 'cnrancher' }}/${{ vars.IMAGE || 'kube-explorer' }}
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=ref,event=branch,suffix=-head
|
||||
- name: Build to Aliyun
|
||||
if: ${{ vars.ALIYUN_REGISTRY != '' }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
labels: ${{ steps.aliyun-meta.outputs.labels }}
|
||||
tags: "${{ steps.aliyun-meta.outputs.tags }}"
|
||||
context: package
|
||||
push: true
|
||||
|
||||
# docker hub multi-arch image
|
||||
- name: Login to Dockerhub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: CI
|
||||
if: startsWith(github.ref, 'refs/heads/')
|
||||
env:
|
||||
CROSS: push
|
||||
run: make github_ci
|
||||
|
||||
- name: CI
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
CROSS: tag
|
||||
run: |
|
||||
make github_ci
|
||||
make release-note
|
||||
|
||||
- name: Prepare for packaging image
|
||||
run: cp dist/* package/
|
||||
- name: Set docker iamge name
|
||||
id: image-name
|
||||
env:
|
||||
REPO_OVERRIDE: ${{ vars.REPO || 'cnrancher' }}
|
||||
IMAGE_OVERRIDE: ${{ vars.IMAGE || 'kube-explorer' }}
|
||||
run: |
|
||||
tag_name=latest;
|
||||
if [[ ${GITHUB_REF} == refs/tags/* ]]; then tag_name=${GITHUB_REF#refs/tags/}; fi;
|
||||
echo "image_name=${REPO_OVERRIDE}/${IMAGE_OVERRIDE}:${tag_name}" >> $GITHUB_OUTPUT;
|
||||
-
|
||||
name: Set up QEMU
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ vars.REPO || 'cnrancher' }}/${{ vars.IMAGE || 'kube-explorer' }}
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
type=ref,event=branch,suffix=-head
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build to Dockerhub
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64/v8
|
||||
tags: "${{ steps.image-name.outputs.image_name }}"
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: "${{ steps.meta.outputs.tags }}"
|
||||
context: package
|
||||
push: true
|
||||
- name: Build to Aliyun
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
tags: registry.cn-shenzhen.aliyuncs.com/${{ steps.image-name.outputs.image_name }}
|
||||
context: package
|
||||
push: true
|
||||
if: ${{ vars.ALIYUN == 'true' }}
|
||||
|
||||
- name: Make release note
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
make release-note
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: dist/kube-explorer-*
|
||||
body_path: dist/release-note
|
||||
draft: true
|
||||
draft: true
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -23,3 +23,7 @@
|
||||
/.vscode
|
||||
/vendor
|
||||
/internal/ui/ui/
|
||||
**/Dockerfile.dapper*
|
||||
!**/Dockerfile.dapper
|
||||
|
||||
dist/
|
||||
|
75
.goreleaser.yaml
Normal file
75
.goreleaser.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
|
||||
# The lines below are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/need to use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
dist: bin
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- id: prod
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
targets:
|
||||
- "darwin_amd64"
|
||||
- "darwin_arm64"
|
||||
- "linux_amd64"
|
||||
- "linux_arm64"
|
||||
- "linux_arm"
|
||||
- "windows_amd64"
|
||||
flags:
|
||||
- -tags=embed
|
||||
binary: '{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}'
|
||||
ldflags: |
|
||||
{{ if ne .Os "darwin" }}
|
||||
-extldflags -static -s
|
||||
{{ else }}
|
||||
-s -w
|
||||
{{ end }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/version.Version={{ .Env.VERSION }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/version.GitCommit={{ .Env.COMMIT }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/config.APIUIVersion={{ .Env.CATTLE_API_UI_VERSION }}
|
||||
no_unique_dist_dir: true
|
||||
- id: dev
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
targets:
|
||||
- "linux_amd64"
|
||||
- "linux_arm64"
|
||||
flags:
|
||||
- -tags=embed
|
||||
binary: '{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}'
|
||||
ldflags: |
|
||||
{{ if ne .Os "darwin" }}
|
||||
-extldflags -static -s
|
||||
{{ else }}
|
||||
-s -w
|
||||
{{ end }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/version.Version={{ .Env.VERSION }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/version.GitCommit={{ .Env.COMMIT }}
|
||||
-X github.com/cnrancher/kube-explorer/internal/config.APIUIVersion={{ .Env.CATTLE_API_UI_VERSION }}
|
||||
no_unique_dist_dir: true
|
||||
upx:
|
||||
- compress: "5"
|
||||
ids:
|
||||
- prod
|
||||
enabled: true
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
@@ -1,3 +1,4 @@
|
||||
FROM goreleaser/goreleaser:v2.3.2 as goreleaser
|
||||
FROM aevea/release-notary:0.9.2 as tools
|
||||
|
||||
FROM registry.suse.com/bci/golang:1.22
|
||||
@@ -8,8 +9,7 @@ ENV HOST_ARCH=${DAPPER_HOST_ARCH} ARCH=${DAPPER_HOST_ARCH}
|
||||
ENV https_proxy=${PROXY} \
|
||||
http_proxy=${PROXY}
|
||||
|
||||
RUN zypper -n install ca-certificates git-core wget curl unzip tar vim less file xz
|
||||
RUN zypper install -y -f docker
|
||||
RUN zypper -n install ca-certificates git-core wget curl unzip tar vim less file xz cosign docker
|
||||
|
||||
ENV UPX_VERSION 4.2.1
|
||||
RUN curl -sL https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${UPX_VERSION}-${ARCH}_linux.tar.xz | tar xvJf - --strip-components=1 -C /tmp && \
|
||||
@@ -18,11 +18,12 @@ RUN curl -sL https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${
|
||||
RUN if [ "${ARCH}" == "amd64" ]; then \
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.54.2; \
|
||||
fi
|
||||
COPY --from=goreleaser /usr/bin/goreleaser /usr/bin/goreleaser
|
||||
COPY --from=tools /app/release-notary /usr/local/bin/
|
||||
ENV CATTLE_DASHBOARD_UI_VERSION="v2.8.0-kube-explorer-ui-rc3"
|
||||
ENV CATTLE_DASHBOARD_UI_VERSION="v2.8.5-kube-explorer-ui-rc1"
|
||||
ENV CATTLE_API_UI_VERSION="1.1.11"
|
||||
|
||||
ENV DAPPER_ENV REPO TAG DRONE_TAG CROSS GOPROXY SKIP_COMPRESS GITHUB_REPOSITORY GITHUB_TOKEN
|
||||
ENV DAPPER_ENV REPO TAG DRONE_TAG CROSS GOPROXY GITHUB_TOKEN GITHUB_REF GITHUB_REF_NAME BUILD_TARGET SKIP_PACKAGE
|
||||
ENV DAPPER_SOURCE /go/src/github.com/cnrancher/kube-explorer
|
||||
ENV DAPPER_OUTPUT ./bin ./dist
|
||||
ENV DAPPER_DOCKER_SOCKET true
|
||||
|
34
deploy/kubectl/path-prefix/Readme.md
Normal file
34
deploy/kubectl/path-prefix/Readme.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Deploy kube-explorer behind proxy with path prefix
|
||||
|
||||
> Supported since v0.5.0
|
||||
|
||||
The kube-explorer dashboard can be exposed behind a proxy and path prefix like `http://your-domain.com/kube-explorer`.
|
||||
|
||||
The deployment examples in this folder are:
|
||||
|
||||
- `nginx ingress`
|
||||
- `traefik ingress`
|
||||
|
||||
## Serve with ingress
|
||||
|
||||
When serving with nginx/traefik ingress controller, the template ingress file needs to be modified. In the `*.tpl` file, you can spot the missing hostname like:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
rules:
|
||||
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
|
||||
```
|
||||
|
||||
Replace your ip to `${MY_UP}`, this will use the [sslip.io](https://sslip.io/) dns service to resolve the hostname to the ingress ip address.
|
||||
|
||||
For the traefik ingress, it is using `v2` version of the traefik ingress schema which use middlewares to modify the proxy request. Both `stripPrefix` and `headers` are used.
|
||||
For the nginx ingress, the annotations `nginx.ingress.kubernetes.io/x-forwarded-prefix` and `nginx.ingress.kubernetes.io/rewrite-target` are used to strip prefix and to add proxy request header.
|
||||
|
||||
## Serve with self-hosted proxy
|
||||
|
||||
If serving the kube-explorer with self-hosted proxy, following modifications are required when proxying:
|
||||
|
||||
- Rewrite the proxy request to strip the path prefix like `rewrite "(?i)/kube-explorer(/|$)(.*)" /$2 break;` in nginx configuration.
|
||||
- Add header `X-API-URL-Prefix` or `X-Forwarded-Prefix` with the path prefix when proxying request like `proxy_set_header X-Forwarded-Prefix "/kube-explorer";` in nginx configuration.
|
||||
|
||||
Then kube-explorer will response the index.html with modified content with path prefix to the browser.
|
24
deploy/kubectl/path-prefix/nginx-ingress.yaml.tpl
Normal file
24
deploy/kubectl/path-prefix/nginx-ingress.yaml.tpl
Normal file
@@ -0,0 +1,24 @@
|
||||
# Note: please replace the host first
|
||||
# To use sslip.io: https://sslip.io/
|
||||
# To get your public IP: curl ipinfo.io/ip
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/x-forwarded-prefix: "/kube-explorer"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
name: kube-explorer-ingress
|
||||
namespace: kube-system
|
||||
spec:
|
||||
rules:
|
||||
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: kube-explorer
|
||||
port:
|
||||
name: http
|
||||
path: /kube-explorer(/|$)(.*)
|
||||
pathType: ImplementationSpecific
|
||||
|
42
deploy/kubectl/path-prefix/traefik-ingress.yaml.tpl
Normal file
42
deploy/kubectl/path-prefix/traefik-ingress.yaml.tpl
Normal file
@@ -0,0 +1,42 @@
|
||||
# Note: please replace the host first
|
||||
# To use sslip.io: https://sslip.io/
|
||||
# To get your public IP: curl ipinfo.io/ip
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: kube-explorer-ingress
|
||||
namespace: kube-system
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.middlewares: kube-system-prefix@kubernetescrd,kube-system-add-header@kubernetescrd
|
||||
spec:
|
||||
rules:
|
||||
- host: "${MY_IP}.sslip.io" # Replace with your actual domain
|
||||
http:
|
||||
paths:
|
||||
- path: /kube-explorer
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: kube-explorer
|
||||
port:
|
||||
name: http
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: prefix
|
||||
namespace: kube-system
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /kube-explorer
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: add-header
|
||||
namespace: kube-system
|
||||
spec:
|
||||
headers:
|
||||
customRequestHeaders:
|
||||
X-Forwarded-Prefix: "/kube-explorer" # Adds
|
31
go.mod
31
go.mod
@@ -2,13 +2,21 @@ module github.com/cnrancher/kube-explorer
|
||||
|
||||
go 1.22.0
|
||||
|
||||
replace k8s.io/client-go => k8s.io/client-go v0.30.1
|
||||
replace (
|
||||
github.com/rancher/steve => github.com/rancher/steve v0.0.0-20240529152548-9fb3e50aa806
|
||||
k8s.io/api => k8s.io/api v0.28.6
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.6
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.28.6
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.28.6
|
||||
k8s.io/client-go => github.com/rancher/client-go v1.28.6-rancher1
|
||||
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/rancher/apiserver v0.0.0-20240708202538-39a6f2535146
|
||||
github.com/rancher/steve v0.0.0-20240709130809-47871606146c
|
||||
github.com/rancher/wrangler/v3 v3.0.0
|
||||
github.com/rancher/apiserver v0.0.0-20240207153744-69b3c2b56f3f
|
||||
github.com/rancher/steve v0.0.0-20240529152548-9fb3e50aa806
|
||||
github.com/rancher/wrangler/v2 v2.1.4
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/urfave/cli v1.22.15
|
||||
golang.org/x/text v0.14.0
|
||||
@@ -26,7 +34,6 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
@@ -41,33 +48,30 @@ require (
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/rancher/dynamiclistener v0.6.0-rc2 // indirect
|
||||
github.com/rancher/dynamiclistener v0.4.0-rc2 // indirect
|
||||
github.com/rancher/kubernetes-provider-detector v0.1.5 // indirect
|
||||
github.com/rancher/lasso v0.0.0-20240705194423-b2a060d103c1 // indirect
|
||||
github.com/rancher/norman v0.0.0-20240708202514-a0127673d1b9 // indirect
|
||||
github.com/rancher/remotedialer v0.3.2 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/urfave/cli/v2 v2.27.1 // indirect
|
||||
@@ -102,13 +106,6 @@ require (
|
||||
k8s.io/kube-aggregator v0.30.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||
modernc.org/libc v1.49.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.29.10 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect
|
||||
sigs.k8s.io/cli-utils v0.35.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
var InsecureSkipTLSVerify bool
|
||||
var SystemDefaultRegistry string
|
||||
var APIUIVersion = "1.1.11"
|
||||
|
||||
var ShellPodImage string
|
||||
|
||||
func Flags() []cli.Flag {
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/cnrancher/kube-explorer/internal/config"
|
||||
"github.com/rancher/steve/pkg/podimpersonation"
|
||||
"github.com/rancher/steve/pkg/stores/proxy"
|
||||
"github.com/rancher/wrangler/v3/pkg/schemas/validation"
|
||||
"github.com/rancher/wrangler/v2/pkg/schemas/validation"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
|
@@ -6,13 +6,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/apiserver/pkg/types"
|
||||
"github.com/rancher/apiserver/pkg/urlbuilder"
|
||||
steveauth "github.com/rancher/steve/pkg/auth"
|
||||
"github.com/rancher/steve/pkg/schema"
|
||||
"github.com/rancher/steve/pkg/server"
|
||||
"github.com/rancher/steve/pkg/server/cli"
|
||||
"github.com/rancher/steve/pkg/server/router"
|
||||
"github.com/rancher/wrangler/v3/pkg/kubeconfig"
|
||||
"github.com/rancher/wrangler/v3/pkg/ratelimit"
|
||||
"github.com/rancher/wrangler/v2/pkg/kubeconfig"
|
||||
"github.com/rancher/wrangler/v2/pkg/ratelimit"
|
||||
|
||||
"github.com/cnrancher/kube-explorer/internal/config"
|
||||
"github.com/cnrancher/kube-explorer/internal/resources/cluster"
|
||||
@@ -20,7 +21,7 @@ import (
|
||||
"github.com/cnrancher/kube-explorer/internal/version"
|
||||
)
|
||||
|
||||
func ToServer(ctx context.Context, c *cli.Config, sqlCache bool) (*server.Server, error) {
|
||||
func ToServer(ctx context.Context, c *cli.Config) (*server.Server, error) {
|
||||
var (
|
||||
auth steveauth.Middleware
|
||||
)
|
||||
@@ -58,10 +59,13 @@ func ToServer(ctx context.Context, c *cli.Config, sqlCache bool) (*server.Server
|
||||
AuthMiddleware: auth,
|
||||
Controllers: controllers,
|
||||
Next: ui,
|
||||
SQLCache: sqlCache,
|
||||
// router needs to hack here
|
||||
Router: func(h router.Handlers) http.Handler {
|
||||
return rewriteLocalCluster(router.Routes(h))
|
||||
return handleProxyHeader(
|
||||
rewriteLocalCluster(
|
||||
router.Routes(h),
|
||||
),
|
||||
)
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -99,3 +103,12 @@ func rewriteLocalCluster(next http.Handler) http.Handler {
|
||||
next.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
||||
func handleProxyHeader(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if value := req.Header.Get("X-Forwarded-Prefix"); value != "" {
|
||||
req.Header.Set(urlbuilder.PrefixHeader, value)
|
||||
}
|
||||
next.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
@@ -132,7 +132,6 @@ func (h *Handler) IndexFile() http.Handler {
|
||||
http.NotFoundHandler().ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write(rtn)
|
||||
}))
|
||||
}
|
||||
|
116
internal/ui/proxy.go
Normal file
116
internal/ui/proxy.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/rancher/apiserver/pkg/urlbuilder"
|
||||
"k8s.io/apimachinery/pkg/util/proxy"
|
||||
)
|
||||
|
||||
type RoundTripFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (r RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return r(req)
|
||||
}
|
||||
|
||||
func proxyMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
scheme := urlbuilder.GetScheme(r)
|
||||
host := urlbuilder.GetHost(r, scheme)
|
||||
pathPrepend := r.Header.Get(urlbuilder.PrefixHeader)
|
||||
|
||||
if scheme == r.URL.Scheme && host == r.URL.Host && pathPrepend == "" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
proxyRoundtrip := proxy.Transport{
|
||||
Scheme: scheme,
|
||||
Host: host,
|
||||
PathPrepend: pathPrepend,
|
||||
RoundTripper: RoundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
rw := &dummyResponseWriter{
|
||||
next: w,
|
||||
header: make(http.Header),
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
return rw.getResponse(r), nil
|
||||
}),
|
||||
}
|
||||
//proxyRoundtripper will write the response in RoundTrip func
|
||||
resp, _ := proxyRoundtrip.RoundTrip(r)
|
||||
responseToWriter(resp, w)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &dummyResponseWriter{}
|
||||
var _ http.Hijacker = &dummyResponseWriter{}
|
||||
|
||||
type dummyResponseWriter struct {
|
||||
next http.ResponseWriter
|
||||
|
||||
header http.Header
|
||||
body bytes.Buffer
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// Hijack implements http.Hijacker.
|
||||
func (drw *dummyResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if h, ok := drw.next.(http.Hijacker); ok {
|
||||
return h.Hijack()
|
||||
}
|
||||
return nil, nil, fmt.Errorf("")
|
||||
}
|
||||
|
||||
// Header implements the http.ResponseWriter interface.
|
||||
func (drw *dummyResponseWriter) Header() http.Header {
|
||||
return drw.header
|
||||
}
|
||||
|
||||
// Write implements the http.ResponseWriter interface.
|
||||
func (drw *dummyResponseWriter) Write(b []byte) (int, error) {
|
||||
return drw.body.Write(b)
|
||||
}
|
||||
|
||||
// WriteHeader implements the http.ResponseWriter interface.
|
||||
func (drw *dummyResponseWriter) WriteHeader(statusCode int) {
|
||||
drw.statusCode = statusCode
|
||||
}
|
||||
|
||||
// GetStatusCode returns the status code written to the response.
|
||||
func (drw *dummyResponseWriter) GetStatusCode() int {
|
||||
if drw.statusCode == 0 {
|
||||
return 200
|
||||
}
|
||||
return drw.statusCode
|
||||
}
|
||||
|
||||
func (drw *dummyResponseWriter) getResponse(req *http.Request) *http.Response {
|
||||
return &http.Response{
|
||||
Status: strconv.Itoa(drw.GetStatusCode()),
|
||||
StatusCode: drw.GetStatusCode(),
|
||||
Proto: "HTTP/1.1",
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
Request: req,
|
||||
Header: drw.header,
|
||||
Body: io.NopCloser(&drw.body),
|
||||
}
|
||||
}
|
||||
|
||||
func responseToWriter(resp *http.Response, writer http.ResponseWriter) {
|
||||
for k, v := range resp.Header {
|
||||
writer.Header()[k] = v
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
writer.WriteHeader(resp.StatusCode)
|
||||
}
|
||||
_, _ = io.Copy(writer, resp.Body)
|
||||
}
|
@@ -27,5 +27,5 @@ func New(opt *Options) (http.Handler, APIUI) {
|
||||
http.Redirect(rw, req, url, http.StatusFound)
|
||||
})
|
||||
|
||||
return router, apiUI(opt)
|
||||
return proxyMiddleware(router), apiUI(opt)
|
||||
}
|
||||
|
4
main.go
4
main.go
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/rancher/steve/pkg/debug"
|
||||
stevecli "github.com/rancher/steve/pkg/server/cli"
|
||||
"github.com/rancher/steve/pkg/version"
|
||||
"github.com/rancher/wrangler/v3/pkg/signals"
|
||||
"github.com/rancher/wrangler/v2/pkg/signals"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
@@ -34,7 +34,7 @@ func main() {
|
||||
func run(_ *cli.Context) error {
|
||||
ctx := signals.SetupSignalContext()
|
||||
keconfig.Debug.MustSetupDebug()
|
||||
s, err := server.ToServer(ctx, &keconfig.Steve, false)
|
||||
s, err := server.ToServer(ctx, &keconfig.Steve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
FROM registry.suse.com/bci/bci-minimal:15.6
|
||||
FROM registry.suse.com/bci/bci-base:15.6
|
||||
ARG TARGETARCH
|
||||
ARG TARGETOS
|
||||
ENV ARCH=${TARGETARCH:-"amd64"} OS=${TARGETOS:-"linux"}
|
||||
COPY entrypoint.sh /usr/bin/
|
||||
RUN zypper install -y catatonit
|
||||
COPY kube-explorer-${OS}-${ARCH} /usr/bin/kube-explorer
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
ENTRYPOINT [ "/usr/bin/catatonit", "--", "kube-explorer" ]
|
||||
|
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
kube-explorer "${@}"
|
@@ -6,77 +6,33 @@ cd "$(dirname $0)/.."
|
||||
|
||||
rm -rf ./bin/* ./dist/*
|
||||
|
||||
OS_ARCH_ARG_LINUX="amd64 arm arm64"
|
||||
OS_ARCH_ARG_DARWIN="amd64 arm64"
|
||||
OS_ARCH_ARG_WINDOWS="amd64"
|
||||
BUILD_TARGET="${BUILD_TARGET:-dev}"
|
||||
CROSS=${CROSS:-}
|
||||
|
||||
LD_INJECT_VALUES="-X github.com/cnrancher/kube-explorer/internal/version.Version=$VERSION
|
||||
-X github.com/cnrancher/kube-explorer/internal/version.GitCommit=$COMMIT
|
||||
-X github.com/cnrancher/kube-explorer/internal/config.APIUIVersion=$CATTLE_API_UI_VERSION"
|
||||
if [[ ${GITHUB_REF} == refs/tags/* ]]; then
|
||||
CROSS=tag
|
||||
elif [ -n "${GITHUB_REF}" ]; then
|
||||
CROSS=push
|
||||
fi
|
||||
|
||||
[ "$(uname)" != "Darwin" ] && LINKFLAGS="-extldflags -static -s"
|
||||
|
||||
case "$CROSS" in
|
||||
"push")
|
||||
for ARCH in ${OS_ARCH_ARG_LINUX}; do
|
||||
OUTPUT_BIN="bin/kube-explorer-linux-$ARCH"
|
||||
echo "Building binary for linux/$ARCH..."
|
||||
GOARCH=$ARCH GOOS=linux CGO_ENABLED=0 go build -tags embed \
|
||||
-ldflags \
|
||||
"$LD_INJECT_VALUES $LINKFLAGS" \
|
||||
-o ${OUTPUT_BIN}
|
||||
done
|
||||
;;
|
||||
case "$CROSS" in
|
||||
"tag")
|
||||
for ARCH in ${OS_ARCH_ARG_LINUX}; do
|
||||
OUTPUT_BIN="bin/kube-explorer-linux-$ARCH"
|
||||
echo "Building binary for linux/$ARCH..."
|
||||
GOARCH=$ARCH GOOS=linux CGO_ENABLED=0 go build -tags embed \
|
||||
-ldflags \
|
||||
"$LD_INJECT_VALUES $LINKFLAGS" \
|
||||
-o ${OUTPUT_BIN}
|
||||
done
|
||||
|
||||
for ARCH in ${OS_ARCH_ARG_DARWIN}; do
|
||||
OUTPUT_BIN="bin/kube-explorer-darwin-$ARCH"
|
||||
echo "Building binary for darwin/$ARCH..."
|
||||
GOARCH=$ARCH GOOS=darwin CGO_ENABLED=0 go build -tags embed \
|
||||
-ldflags \
|
||||
"$LD_INJECT_VALUES" \
|
||||
-o ${OUTPUT_BIN}
|
||||
done
|
||||
|
||||
for ARCH in ${OS_ARCH_ARG_WINDOWS}; do
|
||||
OUTPUT_BIN="bin/kube-explorer-windows-$ARCH.exe"
|
||||
echo "Building binary for windows/$ARCH..."
|
||||
GOARCH=$ARCH GOOS=windows CGO_ENABLED=0 go build -tags embed \
|
||||
-ldflags \
|
||||
"$LD_INJECT_VALUES" \
|
||||
-o ${OUTPUT_BIN}
|
||||
done
|
||||
;;
|
||||
BUILD_TARGET="prod"
|
||||
;;
|
||||
"push")
|
||||
;;
|
||||
*)
|
||||
# only build one for current platform
|
||||
CGO_ENABLED=0 go build -tags embed \
|
||||
-ldflags \
|
||||
"$LD_INJECT_VALUES $LINKFLAGS" \
|
||||
-o "bin/kube-explorer-$(uname | tr '[:upper:]' '[:lower:]')-${ARCH}"
|
||||
;;
|
||||
BUILD_ARG="${BUILD_ARG} --single-target"
|
||||
;;
|
||||
esac
|
||||
|
||||
BUILD_ARG="${BUILD_ARG:-} --skip validate --id ${BUILD_TARGET}"
|
||||
|
||||
mkdir -p "./bin"
|
||||
|
||||
# upx is handled by goreleaser
|
||||
VERSION=${VERSION} COMMIT=${COMMIT} goreleaser build $BUILD_ARG
|
||||
|
||||
mkdir -p "./dist"
|
||||
|
||||
for f in ./bin/*; do
|
||||
filename=$(basename "$f")
|
||||
if [[ $filename != *darwin* && -z "$SKIP_COMPRESS" ]]; then
|
||||
if upx -o "./dist/$filename" "$f"; then
|
||||
echo "UPX done for $filename!"
|
||||
else
|
||||
echo "UPX failed for $filename, copying original file."
|
||||
cp "$f" "./dist/$filename"
|
||||
fi
|
||||
else
|
||||
cp "$f" "./dist/$filename"
|
||||
fi
|
||||
done
|
||||
cp -r bin/kube-explorer-* dist/
|
||||
|
@@ -6,4 +6,6 @@ cd $(dirname $0)
|
||||
./download
|
||||
./validate
|
||||
./build
|
||||
./package
|
||||
if [ -z "${SKIP_PACKAGE}" ]; then
|
||||
./package
|
||||
fi
|
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
./download
|
||||
./validate
|
||||
./build
|
||||
|
@@ -18,3 +18,14 @@ go mod tidy
|
||||
|
||||
echo Verifying modules
|
||||
go mod verify
|
||||
|
||||
dirty_files="$(git status --porcelain --untracked-files=no)"
|
||||
if [ -n "$dirty_files" ]; then
|
||||
echo "Encountered dirty repo! Aborting."
|
||||
echo "If you're seeing this, it means there are uncommitted changes in the repo."
|
||||
echo "If you're seeing this in CI, it probably means that your Go modules aren't tidy, or more generally that running"
|
||||
echo "validation would result in changes to the repo. Make sure you're up to date with the upstream branch and run"
|
||||
echo "'go mod tidy' and commit the changes, if any. The offending changed files are as follows:"
|
||||
echo "$dirty_files"
|
||||
exit 1
|
||||
fi
|
||||
|
@@ -1,11 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ ${GITHUB_REF} == refs/tags/* ]]; then
|
||||
GIT_TAG=${GIT_TAG:-${GITHUB_REF_NAME}}
|
||||
fi
|
||||
|
||||
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
|
||||
DIRTY="-dirty"
|
||||
fi
|
||||
|
||||
COMMIT=$(git rev-parse --short HEAD)
|
||||
GIT_TAG=${DRONE_TAG:-$(git tag -l --contains HEAD | head -n 1)}
|
||||
GIT_TAG=${GIT_TAG:-$(git tag -l --contains HEAD | head -n 1)}
|
||||
|
||||
if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then
|
||||
VERSION=$GIT_TAG
|
||||
|
Reference in New Issue
Block a user