Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add basic authentication for dashboard #955

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cmd/dashboard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ var (
leaderElection bool
leaderElectionNamespace string
leaderElectionLeaseDuration time.Duration

// for basic auth
USERNAME string
PASSWORD string
)

func main() {
Expand All @@ -78,6 +82,12 @@ func main() {
},
}

if v := os.Getenv("USERNAME"); v != "" {
USERNAME = v
}
if v := os.Getenv("PASSWORD"); v != "" {
PASSWORD = v
}
cmd.PersistentFlags().Uint16Var(&port, "port", 8088, "port to listen on")
cmd.PersistentFlags().BoolVar(&devMode, "dev", false, "enable dev mode")
cmd.PersistentFlags().StringVar(&staticDir, "static-dir", "", "static files to serve")
Expand Down Expand Up @@ -150,6 +160,11 @@ func run() {
c.File(filepath.Join(staticDir, path))
})
}
if USERNAME != "" && PASSWORD != "" {
router.Use(gin.BasicAuth(gin.Accounts{
USERNAME: PASSWORD,
}))
}
podApi.Handle(router.Group("/api/v1"))
addr := fmt.Sprintf(":%d", port)
srv := &http.Server{
Expand Down
4 changes: 3 additions & 1 deletion dashboard-ui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import { DarkMode, Question, SelectLang } from '@/components/RightContent'
import { Flex } from 'antd'
import { RuntimeConfig } from 'umi'
import { RequestConfig, RuntimeConfig } from 'umi'

export const request: RequestConfig = {}

// 运行时配置

Expand Down
98 changes: 44 additions & 54 deletions dashboard-ui/src/services/pod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Node as RawNode,
Pod as RawPod,
} from 'kubernetes-types/core/v1'
import { request } from 'umi'

export type Pod = RawPod & {
mountPods?: RawPod[]
Expand Down Expand Up @@ -251,10 +252,12 @@ export const listAppPods = async (args: AppPagingListArgs) => {
const mountPod = args.mountPod || ''
const pageSize = args.pageSize || 20
const current = args.current || 1
const pods = await fetch(
data = await request<{
pods: Pod[]
total: number
}>(
`${host}/api/v1/pods?order=${order}&namespace=${namespace}&name=${name}&pv=${pv}&mountpod=${mountPod}&csinode=${csiNode}&pageSize=${pageSize}&current=${current}`,
)
data = JSON.parse(await pods.text())
} catch (e) {
console.log(`fail to list pods: ${e}`)
return { data: null, success: false }
Expand All @@ -275,74 +278,59 @@ export const listAppPods = async (args: AppPagingListArgs) => {
export const getPod = async (namespace: string, podName: string) => {
let pod: Pod
try {
const rawPod = await fetch(`${host}/api/v1/pod/${namespace}/${podName}/`)
pod = JSON.parse(await rawPod.text())
pod = await request<Pod>(`${host}/api/v1/pod/${namespace}/${podName}/`)
} catch (e) {
console.log(`fail to get pod(${namespace}/${podName}): ${e}`)
return null
}
try {
const mountPods = await fetch(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/mountpods`,
)
pod.mountPods = JSON.parse(await mountPods.text())
} catch (e) {
console.log(`fail to get mount pod for pod(${namespace}/${podName}): ${e}`)
}
try {
const appPods = await fetch(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/apppods`,
)
pod.appPods = JSON.parse(await appPods.text())
} catch (e) {
console.log(`fail to get app pod for pod(${namespace}/${podName}): ${e}`)
}

if (pod.spec?.nodeName) {
try {
const csiNode = await fetch(
`${host}/api/v1/csi-node/${pod.spec?.nodeName}`,
)
pod.csiNode = JSON.parse(await csiNode.text())
} catch (e) {
console.log(`fail to get csi node for pod(${namespace}/${podName}): ${e}`)
}
try {
const node = await fetch(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/node`,
)
pod.node = JSON.parse(await node.text())
} catch (e) {
console.log(`fail to get node for pod(${namespace}/${podName}): ${e}`)
}
}

try {
const events = await fetch(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/events`,
)
let podEvents: Event[] = JSON.parse(await events.text()) || []
podEvents.sort((a, b) => {
const aTime = new Date(a.firstTimestamp || a.eventTime || 0).getTime()
const bTime = new Date(b.firstTimestamp || b.eventTime || 0).getTime()
return bTime - aTime
})
pod.events = podEvents
const [mountPods, appPods, csiNodePod, node, events] = await Promise.all([
request<Pod[]>(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/mountpods`,
),
request<Pod[]>(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/apppods`,
),
pod.spec?.nodeName
? request<Pod>(`${host}/api/v1/csi-node/${pod.spec?.nodeName}`)
: undefined,
pod.spec?.nodeName
? request<RawNode>(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/node`,
)
: undefined,
request<Event[]>(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/events`,
).then((podEvents) => {
podEvents.sort((a, b) => {
const aTime = new Date(a.firstTimestamp || a.eventTime || 0).getTime()
const bTime = new Date(b.firstTimestamp || b.eventTime || 0).getTime()
return bTime - aTime
})
return podEvents
}),
])

pod.mountPods = mountPods
pod.appPods = appPods
pod.csiNode = csiNodePod
pod.node = node
pod.events = events
pod.logs = new Map()
pod.finalStatus = podStatus(pod) || 'Unknown'
} catch (e) {
console.log(`fail to get events for pod(${namespace}/${podName}): ${e}`)
console.log(`fail to get pod(${namespace}/${podName}): ${e}`)
}

return pod
}

export const getLog = async (pod: Pod, container: string) => {
try {
const log = await fetch(
return await request(
`${host}/api/v1/pod/${pod.metadata?.namespace}/${pod.metadata?.name}/logs/${container}`,
)
return await log.text()
} catch (e) {
console.log(
`fail to get log of pod(${pod.metadata?.namespace}/${pod.metadata?.name}/${container}): ${e}`,
Expand Down Expand Up @@ -374,10 +362,12 @@ export const listSystemPods = async (args: SysPagingListArgs) => {
const node = args.node || ''
const pageSize = args.pageSize || 20
const current = args.current || 1
const podList = await fetch(
data = await request<{
pods: Pod[]
total: number
}>(
`${host}/api/v1/syspods?namespace=${namespace}&name=${name}&node=${node}&order=${order}&pageSize=${pageSize}&current=${current}`,
)
data = JSON.parse(await podList.text())
} catch (e) {
console.log(`fail to list sys pods: ${e}`)
return { data: null, success: false }
Expand Down
44 changes: 18 additions & 26 deletions dashboard-ui/src/services/pv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
PersistentVolumeClaim,
} from 'kubernetes-types/core/v1'
import { StorageClass } from 'kubernetes-types/storage/v1'
import { request } from 'umi'

export type PV = PersistentVolume & {
Pod: {
Expand Down Expand Up @@ -82,10 +83,12 @@ export const listPV = async (args: PVPagingListArgs) => {
const sc = args.sc || ''
const pageSize = args.pageSize || 20
const current = args.current || 1
const rawPV = await fetch(
data = await request<{
pvs: PV[]
total: number
}>(
`${host}/api/v1/pvs?order=${order}&name=${name}&pvc=${pvc}&sc=${sc}&pageSize=${pageSize}&current=${current}`,
)
data = JSON.parse(await rawPV.text())
} catch (e) {
console.log(`fail to list pv`)
return { data: null, success: false }
Expand Down Expand Up @@ -124,10 +127,12 @@ export const listPVC = async (args: PVCPagingListArgs) => {
const sc = args.sc || ''
const pageSize = args.pageSize || 20
const current = args.current || 1
const rawPVC = await fetch(
data = await request<{
pvcs: PVC[]
total: number
}>(
`${host}/api/v1/pvcs?order=${order}&namespace=${namespace}&name=${name}&pv=${pv}&sc=${sc}&pageSize=${pageSize}&current=${current}`,
)
data = JSON.parse(await rawPVC.text())
} catch (e) {
console.log(`fail to list pvc`)
return { data: null, success: false }
Expand All @@ -150,8 +155,7 @@ export interface SCPagingListArgs {
export const listStorageClass = async (args: SCPagingListArgs) => {
let data: StorageClass[] = []
try {
const rawSC = await fetch(`${host}/api/v1/storageclasses`)
data = JSON.parse(await rawSC.text())
data = await request<StorageClass[]>(`${host}/api/v1/storageclasses`)
} catch (e) {
console.log(`fail to list sc`)
return { data: [], success: false }
Expand Down Expand Up @@ -186,8 +190,7 @@ export const listStorageClass = async (args: SCPagingListArgs) => {

export const getPV = async (pvName: string) => {
try {
const rawPV = await fetch(`${host}/api/v1/pv/${pvName}/`)
return JSON.parse(await rawPV.text())
return await fetch(`${host}/api/v1/pv/${pvName}/`)
} catch (e) {
console.log(`fail to get pv(${pvName}): ${e}`)
return null
Expand All @@ -196,8 +199,7 @@ export const getPV = async (pvName: string) => {

export const getPVEvents = async (pvName: string) => {
try {
const events = await fetch(`${host}/api/v1/pv/${pvName}/events`)
return JSON.parse(await events.text())
return await fetch(`${host}/api/v1/pv/${pvName}/events`)
} catch (e) {
console.log(`fail to get pv events (${pvName}): ${e}`)
return null
Expand All @@ -206,8 +208,7 @@ export const getPVEvents = async (pvName: string) => {

export const getPVC = async (namespace: string, pvcName: string) => {
try {
const rawPV = await fetch(`${host}/api/v1/pvc/${namespace}/${pvcName}/`)
return JSON.parse(await rawPV.text())
return await request(`${host}/api/v1/pvc/${namespace}/${pvcName}/`)
} catch (e) {
console.log(`fail to get pvc(${namespace}/${pvcName}): ${e}`)
return null
Expand All @@ -216,10 +217,7 @@ export const getPVC = async (namespace: string, pvcName: string) => {

export const getPVCEvents = async (namespace: string, pvcName: string) => {
try {
const events = await fetch(
`${host}/api/v1/pvc/${namespace}/${pvcName}/events`,
)
return JSON.parse(await events.text())
return await request(`${host}/api/v1/pvc/${namespace}/${pvcName}/events`)
} catch (e) {
console.log(`fail to get pvc(${namespace}/${pvcName}): ${e}`)
return null
Expand All @@ -228,8 +226,7 @@ export const getPVCEvents = async (namespace: string, pvcName: string) => {

export const getSC = async (scName: string) => {
try {
const rawSC = await fetch(`${host}/api/v1/storageclass/${scName}/`)
return JSON.parse(await rawSC.text())
return await request(`${host}/api/v1/storageclass/${scName}/`)
} catch (e) {
console.log(`fail to get sc (${scName}): ${e}`)
return null
Expand All @@ -238,10 +235,7 @@ export const getSC = async (scName: string) => {

export const getMountPodOfPVC = async (namespace: string, pvcName: string) => {
try {
const rawPod = await fetch(
`${host}/api/v1/pvc/${namespace}/${pvcName}/mountpods`,
)
return JSON.parse(await rawPod.text())
return await request(`${host}/api/v1/pvc/${namespace}/${pvcName}/mountpods`)
} catch (e) {
console.log(`fail to get mountpod of pvc(${namespace}/${pvcName}): ${e}`)
return null
Expand All @@ -250,8 +244,7 @@ export const getMountPodOfPVC = async (namespace: string, pvcName: string) => {

export const getMountPodOfPV = async (pvName: string) => {
try {
const rawPod = await fetch(`${host}/api/v1/pv/${pvName}/mountpods`)
return JSON.parse(await rawPod.text())
return await request(`${host}/api/v1/pv/${pvName}/mountpods`)
} catch (e) {
console.log(`fail to get mountpod of pv (${pvName}): ${e}`)
return null
Expand All @@ -260,8 +253,7 @@ export const getMountPodOfPV = async (pvName: string) => {

export const getPVOfSC = async (scName: string) => {
try {
const pvs = await fetch(`${host}/api/v1/storageclass/${scName}/pvs`)
return JSON.parse(await pvs.text())
return await request(`${host}/api/v1/storageclass/${scName}/pvs`)
} catch (e) {
console.log(`fail to get pvs of sc (${scName}): ${e}`)
return null
Expand Down
Loading