-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
67 changed files
with
867 additions
and
466 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import k8s from '@kubernetes/client-node'; | ||
import { lists as listNamespace } from '../k8s/Namespace.js'; | ||
import {kc, cache, applyFilter, applyFieldSelection, getByPath, getMeta } from '../k8slibs.js'; | ||
import { knowledge } from '../knowledge.js' | ||
const k8sApi = kc.makeApiClient(k8s.CoreV1Api); | ||
const short2plural = (short:string) => short.toLowerCase()+'s' | ||
export const mutations = { | ||
}; | ||
export const lists = { | ||
}; | ||
export const queries = { | ||
}; | ||
export const resolvers = { | ||
coreContainer: { | ||
getcoreLog: async (cont, args: object) => { | ||
let lst:object|undefined|null = cache.get(`getcoreLog-${cont['namespace']}-${cont['pod_name']}-${cont['name']}`) | ||
const perms = (cache.get(`permissions`)) as { apiGroup: string, resource: string, verb: string }[]; | ||
if (perms!=undefined && lst==undefined) { | ||
if(!perms.reduce((res,perm) => res||((perm.verb=='*'||perm.verb=='get')&&( | ||
['*','pods/log'].includes(perm.resource) && ['*',''].includes(perm.apiGroup) | ||
)), false)) { | ||
cache.set(`getcoreLog-${cont['namespace']}-${cont['pod_name']}-${cont['name']}`, undefined, 60); | ||
return [] | ||
} | ||
} | ||
if (lst==undefined && typeof cont['namespace']==='string' && typeof cont['pod_name']==='string' && typeof cont['name']==='string') { | ||
try { | ||
const res = (await k8sApi.readNamespacedPodLog(cont['pod_name'],cont['namespace'],cont['name'],false,undefined,undefined,undefined,undefined,undefined,typeof args['maxLines']== 'number'?args['maxLines']:500)).body | ||
if (typeof res==='string') { | ||
lst = {lines: (res as string).split('\n')} | ||
cache.set(`getcoreLog-${cont['namespace']}-${cont['pod_name']}-${cont['name']}`, lst, 2); | ||
} else { | ||
lst = {lines: []} | ||
cache.set(`getcoreLog-${cont['namespace']}-${cont['pod_name']}-${cont['name']}`, lst, 2); | ||
} | ||
} catch (err) { | ||
if (typeof err === 'object' && (err as object)['body'] !=undefined) { | ||
if ((err as object)['body']['reason']!='Forbidden') { | ||
console.error('error', (err as object)['body']); | ||
} else { | ||
cache.set(`getcoreLog-${cont['namespace']}-${cont['pod_name']}-${cont['name']}`, undefined, 2); | ||
} | ||
} else {console.error('error', err)} | ||
return null | ||
} | ||
} | ||
return lst | ||
}, | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import k8s from '@kubernetes/client-node'; | ||
import { lists as listNamespace } from '../k8s/Namespace.js'; | ||
import {kc, cache, applyFilter, applyFieldSelection} from '../k8slibs.js'; | ||
import { knowledge } from '../knowledge.js' | ||
const k8sApi = kc.makeApiClient(k8s.CoreV1Api); | ||
const short2plural = (short:string) => short.toLowerCase()+'s' | ||
export const mutations = { | ||
}; | ||
export const lists = { | ||
coreEvent: async (parent, args: object) => { | ||
let lst:Array<object>|undefined = cache.get('coreEvent') | ||
const perms = (cache.get(`permissions`)) as { apiGroup: string, resource: string, verb: string }[]; | ||
if (perms!=undefined && lst==undefined) { | ||
if(!perms.reduce((res,perm) => res||((perm.verb=='*'||perm.verb=='list')&&( | ||
(perm.resource=='*' && perm.apiGroup=='*') || | ||
(perm.resource=='*' && knowledge.filter(o=>o.group=='core'&&o.short=='Event'&&perm.apiGroup==o.apiGroup).length>0) || | ||
(knowledge.filter(o=>o.group=='k8s'&&o.short=='APIService'&&(perm.apiGroup=='*'||perm.apiGroup==o.apiGroup)).map(o=>short2plural(o.short)).includes(perm.resource)) | ||
)), false)) { | ||
cache.set('coreEvent', [], 60); | ||
return [] | ||
} | ||
} | ||
if (lst==undefined) { | ||
try { | ||
const res = await k8sApi.listEventForAllNamespaces() | ||
lst = ((res as object)['body']['items'] as Array<object>) | ||
cache.set('coreEvent', lst, 2); | ||
} catch (err) { | ||
if (typeof err === 'object' && (err as object)['body'] !=undefined) { | ||
if ((err as object)['body']['reason']!='Forbidden') { | ||
console.error('error', (err as object)['body']); | ||
} else { | ||
try { | ||
const nss = await listNamespace.k8sNamespace(parent, args) | ||
const lst = (await Promise.all(nss.map(n=>n['metadata']['name']).map(async (ns)=>{ | ||
return (await k8sApi.listNamespacedEvent(ns)).body.items | ||
}))).flat().filter((v)=>v!=null) | ||
cache.set('coreEvent', lst, 2); | ||
return lst.filter(o=>typeof parent != 'object' || parent==null || ( | ||
o['involvedObject']!=undefined && o['involvedObject']['name'] == parent['metadata']['name'] && o['involvedObject']['namespace'] == parent['metadata']['namespace'] | ||
)).filter(o=> typeof args['namespace'] != 'string' || ( | ||
o['involvedObject']!=undefined && o['involvedObject']['namespace']==args['namespace'] | ||
)).filter(o=>applyFilter(o,args)).map(o=>applyFieldSelection(o,args)) | ||
} catch (err) { | ||
if (typeof err === 'object' && (err as object)['body'] !=undefined) { | ||
if ((err as object)['body']['reason']!='Forbidden') { | ||
console.error('error', (err as object)['body']); | ||
} else { | ||
cache.set('coreEvent', [], 2); | ||
} | ||
} else {console.error('error', err)} | ||
return [] | ||
} | ||
} | ||
} else {console.error('error', err)} | ||
return [] | ||
} | ||
} | ||
return lst.filter(o=>typeof parent != 'object' || parent==null || ( | ||
o['involvedObject']!=undefined && o['involvedObject']['name'] == parent['metadata']['name'] && o['involvedObject']['namespace'] == parent['metadata']['namespace'] | ||
)).filter(o=> typeof args['namespace'] != 'string' || ( | ||
o['involvedObject']!=undefined && o['involvedObject']['namespace']==args['namespace'] | ||
)).filter(o=>applyFilter(o,args)).map(o=>applyFieldSelection(o,args)) | ||
} | ||
}; | ||
export const queries = { | ||
coreEvent: lists.coreEvent, | ||
}; | ||
export const resolvers = { | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,23 @@ | ||
// noGramoGenerator | ||
import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json'; | ||
import { gramoConfig } from '../../config.js' | ||
import { queries as containerQueries, resolvers as containerResolvers, mutations as containerMutations } from './Container.js'; | ||
import { queries as eventQueries, resolvers as eventResolvers, mutations as eventMutations } from './Event.js'; | ||
|
||
export const queries = { | ||
gramoConfig: () => gramoConfig, | ||
...containerQueries, | ||
...eventQueries, | ||
}; | ||
|
||
export const resolvers = { | ||
JSON: GraphQLJSON, | ||
JSONObject: GraphQLJSONObject | ||
JSONObject: GraphQLJSONObject, | ||
...containerResolvers, | ||
...eventResolvers, | ||
}; | ||
|
||
export const mutations = { | ||
...containerMutations, | ||
...eventMutations, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<script setup lang="ts"> | ||
import { onMounted } from "vue"; | ||
import { elude, getColor, getConditionColor} from "../../libs/core/" | ||
import { usePod, getProperties, PodDefinition } from '../../libs/k8s/Pod.js' | ||
import { colorPod, iconPod } from '../../libs/k8s/custom.js' | ||
import { QTableColumn } from 'quasar' | ||
import { ref, useCore, tableColumnAlign } from '../../libs/core' | ||
const { can, writeProperties, onlyReadProperties, toParentView, viewer, viewerUpdate, toEdit, actionDelete, setNamespacedItemFromRoute } = usePod();setNamespacedItemFromRoute(); | ||
defineEmits(['refresh','on-delete']); | ||
const props=withDefaults(defineProps<{model: object[], useAction?:boolean, useRefresh?: boolean, showNamespace?:boolean}>(),{ | ||
useAction: false, | ||
useRefresh: true, | ||
showNamespace: false, | ||
}); | ||
console.log('ContainerList',props.model) | ||
const tab=ref('list') | ||
const container=ref(props.model.map(c=>c['name'])[0]) | ||
const { pagination } = useCore(); | ||
const ContainerColumns:Array<QTableColumn> = ((props.showNamespace?[{name: 'Namespace', label: 'Namespace', field: row => row.namespace, sortable: true, align: tableColumnAlign.left}]:[]) as QTableColumn[]).concat([ | ||
{name: 'Init', label: 'Init?', field: row => row.init?'init':'main', sortable: true, align: tableColumnAlign.left}, | ||
{name: 'Name', label: 'Name', field: row => row.name, sortable: true, align: tableColumnAlign.left}, | ||
{name: 'Image', label: 'Image', field: row => row.spec.image, sortable: true, align: tableColumnAlign.left}, | ||
{name: 'Status', label: 'Status', field: row => null, sortable: true, align: tableColumnAlign.left}, | ||
{name: 'Action', label: 'Action', field: row => null, sortable: true, align: tableColumnAlign.left}, | ||
] as QTableColumn[]); | ||
const filter = ref(''); | ||
onMounted(() => { | ||
viewerUpdate(onlyReadProperties(props.model)); | ||
}) | ||
function switchToLog(obj) { | ||
container.value=obj['name'] | ||
tab.value='logs' | ||
} | ||
</script> | ||
<template> | ||
<q-card bordered class="q-ma-sm"> | ||
<q-tabs v-model="tab" :class="`bg-${ colorPod } text-grey-2`" active-color="white" align="justify"> | ||
<q-avatar :icon="iconPod" /> | ||
<q-tab label="Containers" name="list" /> | ||
<q-tab label="Logs" name="logs" /> | ||
</q-tabs> | ||
<q-tab-panels v-model="tab" animated> | ||
<q-tab-panel name="list" :class="`bg-${ colorPod }-1`"> | ||
<q-table :rows="model" :class="`no-shadow bg-${ colorPod }-1`" :columns="ContainerColumns" v-model:pagination="pagination" :filter="filter" hide-bottom> | ||
<template v-slot:body-cell-Status="props"> | ||
<q-td :props="props"> | ||
<q-chip class="float-right text-white text-capitalize" v-if="typeof props.row.status.state.terminated==='object'" | ||
:label="props.row.status.state.terminated.reason" :color="props.row.status.state.terminated.exitCode==0?'positive':'negative'"> | ||
<q-tooltip>exit code :{{ props.row.status.state.terminated.exitCode }}</q-tooltip> | ||
</q-chip> | ||
<q-chip class="float-right text-white text-capitalize" v-if="typeof props.row.status.state.running==='object'" | ||
label="Running" color="positive"> | ||
<q-tooltip>Started at:{{ props.row.status.state.running.startedAt }}</q-tooltip> | ||
</q-chip> | ||
</q-td> | ||
</template> | ||
<template v-slot:body-cell-Action="props"> | ||
<q-td :props="props"> | ||
<q-btn icon="output" size="sm" class="q-ml-sm" flat dense @click="switchToLog(props.row)"> | ||
<q-tooltip>View {{ props.row.name }} logs</q-tooltip> | ||
</q-btn> | ||
</q-td> | ||
</template> | ||
</q-table> | ||
</q-tab-panel> | ||
<q-tab-panel name="logs" :class="`bg-${ colorPod }-1`"> | ||
<q-toolbar :class="`bg-${ colorPod } text-white q-my-md shadow-2`"> | ||
<q-space /> | ||
<q-select v-model="container" :options="model.map(o=>o['name'])" label="Container" label-color="white" style="min-width: 350px"> | ||
</q-select> | ||
<q-space /> | ||
</q-toolbar> | ||
<pre v-if="model.filter(c=>c['name']==container).length>0" class="bg-black text-white"> | ||
{{ model.filter(c=>c['name']==container)[0]['getcoreLog']['lines'].join('\n') }} | ||
</pre> | ||
</q-tab-panel> | ||
</q-tab-panels> | ||
</q-card> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<script setup lang="ts"> | ||
defineEmits(['refresh','on-delete']); | ||
const props=withDefaults(defineProps<{model: object[], useAction?:boolean, useRefresh?: boolean, showNamespace?:boolean}>(),{ | ||
useAction: false, | ||
useRefresh: true, | ||
showNamespace: false, | ||
}); | ||
console.log('EventList',props.model) | ||
</script> | ||
<template> | ||
<q-timeline dense> | ||
<q-timeline-entry v-for="(item, key) in model" v-bind:key="key" | ||
:title="item['reason']" | ||
:subtitle="item['metadata']['creationTimestamp']" | ||
:color="item['type']=='Warning'?'warning':'secondary'" | ||
:icon="item['type']=='Warning'?'warning_amber':undefined" | ||
:body="item['message']" | ||
/> | ||
|
||
<q-timeline-entry | ||
title="Event Title" | ||
subtitle="February 21, 1986" | ||
icon="delete" | ||
> | ||
<div> | ||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. | ||
</div> | ||
</q-timeline-entry> | ||
|
||
<q-timeline-entry | ||
title="Event Title" | ||
subtitle="February 22, 1986" | ||
color="orange" | ||
icon="done_all" | ||
> | ||
<div> | ||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. | ||
</div> | ||
</q-timeline-entry> | ||
</q-timeline> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<script setup lang="ts"> | ||
import { ref } from 'vue' | ||
import { useNavigationStore } from '../../stores' | ||
const navigation = useNavigationStore() | ||
const options = ref([ | ||
{label: 'off', value: undefined}, | ||
{label: '2s', value: 2000}, | ||
{label: '10s', value: 10000}, | ||
{label: '1m', value: 60000}, | ||
{label: '2m', value: 120000}, | ||
{label: '5m', value: 60000}, | ||
]); | ||
const model = ref(options.value[0]) | ||
function onRefreshChange() { | ||
navigation.setPoolInterval(model.value.value) | ||
} | ||
navigation.setPoolInterval(model.value.value) | ||
</script> | ||
<template> | ||
<q-select | ||
v-model="model" | ||
@update:model-value="onRefreshChange" | ||
:options="options" standout> | ||
<template v-slot:prepend> | ||
<q-icon name="refresh" /> | ||
</template> | ||
</q-select> | ||
</template> |
Oops, something went wrong.