From 135b1c79e9928b5701f73fd7d50ae6906a5e14f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Huss?= Date: Fri, 15 Mar 2024 17:10:27 +0100 Subject: [PATCH] 0.2.3 CRD improvements --- .gitignore | 1 + back/resolvers/core/CrdObject.ts | 122 ++++++++++++++++++ back/resolvers/core/custom.ts | 4 + back/schema/core.graphql | 13 ++ front/components/charts/stackedBarChart.vue | 2 +- front/components/core/AdviceList.vue | 2 +- front/components/core/AdviceOverview.vue | 12 +- front/components/core/AllProblemOverview.vue | 21 ++- front/components/core/ContainerList.vue | 28 ++-- front/components/core/CrdObjectEdit.vue | 56 ++++++++ front/components/core/CrdObjectList.vue | 62 +++++++++ front/components/core/CrdObjectMeta.vue | 97 ++++++++++++++ front/components/core/CrdObjectView.vue | 121 +++++++++++++++++ front/components/core/MetadataNew.vue | 5 +- front/components/core/MetadataView.vue | 9 +- front/components/core/MonacoEditor.vue | 1 - front/components/core/OpenApiEdit.vue | 22 ++-- front/components/core/OpenApiEditArray.vue | 2 +- front/components/core/OpenApiEditNumber.vue | 3 +- front/components/core/OpenApiEditObject.vue | 2 +- front/components/core/OpenApiEditString.vue | 3 +- .../core/OpenApiEditUndefObject.vue | 2 +- front/components/core/ProblemList.vue | 2 +- front/components/core/ProblemOverview.vue | 8 +- front/components/core/UrlList.vue | 5 +- front/components/navigation/BreadCrumbs.vue | 8 +- .../navigation/RefreshRateSelector.vue | 4 +- front/components/vynil/CategoryList.vue | 7 +- front/components/vynil/CategoryMeta.vue | 5 +- front/components/vynil/PackageList.vue | 15 ++- front/components/vynil/PackageMeta.vue | 17 +-- front/i18n/en.json | 55 +++++++- front/i18n/fr.json | 62 +++++++-- front/index.ts | 17 ++- front/libs/certmanager/custom.ts | 29 +++-- front/libs/core/crdObject.ts | 99 ++++++++++++++ front/libs/core/custom.ts | 1 + front/libs/core/index.ts | 5 +- front/libs/fluxcd/custom.ts | 6 +- front/libs/jaegertracing/custom.ts | 2 +- front/libs/k8s/custom.ts | 7 +- front/libs/vynil/custom.ts | 4 +- front/libs/zalando/custom.ts | 17 +-- front/pages/core/CrdObjectEdit.vue | 98 ++++++++++++++ front/pages/core/CrdObjectNew.vue | 98 ++++++++++++++ front/pages/core/CrdObjectView.vue | 85 ++++++++++++ front/pages/install/vynil/DistribView.vue | 5 +- front/pages/install/vynil/InstallView.vue | 5 +- .../core/clusteredObject.create.graphql | 14 ++ .../core/clusteredObject.delete.graphql | 14 ++ .../core/clusteredObject.patch.graphql | 13 ++ front/queries/core/crdObject.read.graphql | 21 +++ .../core/namespacedObject.create.graphql | 15 +++ .../core/namespacedObject.delete.graphql | 15 +++ .../core/namespacedObject.patch.graphql | 14 ++ front/stores/navigation.ts | 1 + package.json | 4 +- utils/gen.ts | 1 + utils/generator/back/obj.resolvers.ts.hbs | 9 ++ utils/generator/config.ts | 7 + .../front/all.query.read.graphql.hbs | 22 +++- .../generator/front/grp.pages.advices.vue.hbs | 2 +- .../front/grp.pages.dashboard.vue.hbs | 2 +- .../front/grp.query.read.graphql.hbs | 22 +++- utils/generator/front/grp.routes.ts.hbs | 96 +++++++++++++- .../front/obj.components.edit.vue.hbs | 32 ++--- .../front/obj.components.list.vue.hbs | 18 +-- .../front/obj.components.meta.vue.hbs | 12 +- .../front/obj.components.status.vue.hbs | 10 +- .../front/obj.components.view.vue.hbs | 27 ++-- utils/generator/front/obj.lib.ts.hbs | 29 ++--- utils/generator/front/obj.pages.edit.vue.hbs | 21 ++- utils/generator/front/obj.pages.list.vue.hbs | 11 +- utils/generator/front/obj.pages.new.vue.hbs | 29 ++--- utils/generator/front/obj.pages.view.vue.hbs | 19 ++- .../front/obj.query.read.graphql.hbs | 12 ++ .../partials/back/list.resolver.ts.hbs | 2 +- .../partials/front/extra.fields.vue.hbs | 2 +- .../partials/front/name.fields.vue.hbs | 2 +- utils/generator/partials/resolvers/crd.ts.hbs | 87 +++++++++++++ utils/generator/partials/resolvers/k8s.ts.hbs | 12 +- 81 files changed, 1562 insertions(+), 291 deletions(-) create mode 100644 back/resolvers/core/CrdObject.ts create mode 100644 front/components/core/CrdObjectEdit.vue create mode 100644 front/components/core/CrdObjectList.vue create mode 100644 front/components/core/CrdObjectMeta.vue create mode 100644 front/components/core/CrdObjectView.vue create mode 100644 front/libs/core/crdObject.ts create mode 100644 front/pages/core/CrdObjectEdit.vue create mode 100644 front/pages/core/CrdObjectNew.vue create mode 100644 front/pages/core/CrdObjectView.vue create mode 100644 front/queries/core/clusteredObject.create.graphql create mode 100644 front/queries/core/clusteredObject.delete.graphql create mode 100644 front/queries/core/clusteredObject.patch.graphql create mode 100644 front/queries/core/crdObject.read.graphql create mode 100644 front/queries/core/namespacedObject.create.graphql create mode 100644 front/queries/core/namespacedObject.delete.graphql create mode 100644 front/queries/core/namespacedObject.patch.graphql create mode 100644 utils/generator/partials/resolvers/crd.ts.hbs diff --git a/.gitignore b/.gitignore index 15d976a7..354881f4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ !/front/libs/i18n/* !/front/libs/core/* /front/pages/**/*.vue +!/front/pages/core/*.vue !/front/pages/install/vynil/DistribView.vue !/front/pages/install/vynil/InstallView.vue !/front/pages/install/vynil/InstallEdit.vue diff --git a/back/resolvers/core/CrdObject.ts b/back/resolvers/core/CrdObject.ts new file mode 100644 index 00000000..a3c6c0b4 --- /dev/null +++ b/back/resolvers/core/CrdObject.ts @@ -0,0 +1,122 @@ +import k8s from '@kubernetes/client-node'; +import rfc6902 from 'rfc6902'; +import {kc, getMeta, getMetaNS } from '../k8slibs.js'; +const k8sApi = kc.makeApiClient(k8s.CustomObjectsApi); +export const mutations = { + clusteredCrdObjectCreate: async (_parent, args: object) => { + const payload = { + apiVersion: `${args['group']}/${args['version']}`, + kind: args['kind'], + metadata: getMeta(args), + "spec": args['spec'], + } + try { + const res = await k8sApi.createClusterCustomObject(args['group'],args['version'],args['plural'], payload) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, + clusteredCrdObjectDelete: async (_parent, args: object) => { + try { + const res = await k8sApi.deleteClusterCustomObject(args['group'],args['version'],args['plural'], args['name']) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, + clusteredCrdObjectPatch: async (_parent, args: object) => { + const request = { + apiVersion: `${args['group']}/${args['version']}`, + kind: args['kind'], + metadata: getMeta(args), + } + if (args['spec'] != undefined && args['spec'] != null) + request["spec"] = args['spec']; + try { + const resGet = await k8sApi.getClusterCustomObject(args['group'],args['version'],args['plural'], args['metadata']['name']) + const payload = rfc6902.createPatch(resGet.body,request).filter(rule => !rule.path.startsWith('/status') && !['/metadata/creationTimestamp', '/metadata/finalizers', '/metadata/generation', '/metadata/managedFields', '/metadata/resourceVersion','/metadata/uid'].includes(rule.path) ) + const options = { "headers": { "Content-type": k8s.PatchUtils.PATCH_FORMAT_JSON_PATCH}}; + const res = await k8sApi.patchClusterCustomObject(args['group'],args['version'],args['plural'], args['metadata']['name'], payload, undefined, undefined, undefined, options) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, + namespacedCrdObjectCreate: async (_parent, args: object) => { + const payload = { + apiVersion: `${args['group']}/${args['version']}`, + kind: args['kind'], + metadata: getMetaNS(args), + "spec": args['spec'], + } + try { + const res = await k8sApi.createNamespacedCustomObject(args['group'],args['version'],args['metadata']['namespace'],args['plural'], payload) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, + namespacedCrdObjectDelete: async (_parent, args: object) => { + try { + const res = await k8sApi.deleteNamespacedCustomObject(args['group'],args['version'],args['namespace'],args['plural'], args['name']) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, + namespacedCrdObjectPatch: async (_parent, args: object) => { + const request = { + apiVersion: `${args['group']}/${args['version']}`, + kind: args['kind'], + metadata: getMetaNS(args), + } + if (args['spec'] != undefined && args['spec'] != null) + request["spec"] = args['spec']; + try { + const resGet = await k8sApi.getNamespacedCustomObject(args['group'],args['version'],args['metadata']['namespace'],args['plural'], args['metadata']['name']) + const payload = rfc6902.createPatch(resGet.body,request).filter(rule => !rule.path.startsWith('/status') && !['/metadata/creationTimestamp', '/metadata/finalizers', '/metadata/generation', '/metadata/managedFields', '/metadata/resourceVersion','/metadata/uid'].includes(rule.path) ) + const options = { "headers": { "Content-type": k8s.PatchUtils.PATCH_FORMAT_JSON_PATCH}}; + const res = await k8sApi.patchNamespacedCustomObject(args['group'],args['version'],args['metadata']['namespace'],args['plural'], args['metadata']['name'], payload, undefined, undefined, undefined, options) + return res.body + } catch (err) { + if (typeof err === 'object' && (err as object)['body'] !=undefined && (err as object)['statusCode'] !=undefined) { + if ((err as object)['statusCode'] != 404 && (err as object)['body']['reason']!='Forbidden') { + console.error('error', (err as object)['body']); + } + } else {console.error('error', err)} + } + return null + }, +}; +export const lists = { +}; +export const queries = { +}; +export const resolvers = { +}; diff --git a/back/resolvers/core/custom.ts b/back/resolvers/core/custom.ts index b572d0ed..4b364314 100644 --- a/back/resolvers/core/custom.ts +++ b/back/resolvers/core/custom.ts @@ -3,11 +3,13 @@ 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'; +import { queries as crdObjectQueries, resolvers as crdObjectResolvers, mutations as crdObjectMutations } from './CrdObject.js'; export const queries = { gramoConfig: () => gramoConfig, ...containerQueries, ...eventQueries, + ...crdObjectQueries, }; export const resolvers = { @@ -15,9 +17,11 @@ export const resolvers = { JSONObject: GraphQLJSONObject, ...containerResolvers, ...eventResolvers, + ...crdObjectResolvers, }; export const mutations = { ...containerMutations, ...eventMutations, + ...crdObjectMutations, }; diff --git a/back/schema/core.graphql b/back/schema/core.graphql index ce2edfac..5846b2c9 100644 --- a/back/schema/core.graphql +++ b/back/schema/core.graphql @@ -114,6 +114,11 @@ type coreUrl { host: String path: String } +type coreCrdObject { + metadata: metadata + spec: JSONObject + status: JSONObject +} type coreEvent { metadata: metadata source: JSONObject @@ -152,4 +157,12 @@ type Query { coreEvent(params: queryParameters): [coreEvent] vynilCategory(params: queryParameters): [vynilCategory] vynilPackage(params: queryParameters): [vynilPackage] +} +type Mutation { + namespacedCrdObjectCreate(group: String!, version: String!, plural: String!, kind: String!, metadata: metadataInput!, spec: JSONObject): coreCrdObject + namespacedCrdObjectPatch(group: String!, version: String!, plural: String!, kind: String!, metadata: metadataInput!, spec: JSONObject): coreCrdObject + namespacedCrdObjectDelete(group: String!, version: String!, plural: String!, namespace: String!, name: String!): coreCrdObject + clusteredCrdObjectCreate(group: String!, version: String!, plural: String!, kind: String!, metadata: metadataInput!, spec: JSONObject): coreCrdObject + clusteredCrdObjectPatch(group: String!, version: String!, plural: String!, kind: String!, metadata: metadataInput!, spec: JSONObject): coreCrdObject + clusteredCrdObjectDelete(group: String!, version: String!, plural: String!, name: String!): coreCrdObject } \ No newline at end of file diff --git a/front/components/charts/stackedBarChart.vue b/front/components/charts/stackedBarChart.vue index ceb2023b..987119a5 100644 --- a/front/components/charts/stackedBarChart.vue +++ b/front/components/charts/stackedBarChart.vue @@ -22,7 +22,7 @@ const svgRoot = ref(null); const series = d3.stack().keys(d3.union(props.datum.map(props.axisColor))).value(([, D], key) => props.getVal(D.get(key)))(d3.index(props.datum, props.axisX, props.axisColor)); const x = d3.scaleBand().domain(d3.groupSort(props.datum, D => -d3.sum(D, props.getVal), props.axisX)).range([marginLeft, options.value.width - marginRight]).padding(0.1); const y = d3.scaleLinear().domain([0, d3.max(series, d => d3.max(d, d => d[1]))]).rangeRound([options.value.height - marginBottom, marginTop]); -const color = props.datum.length>1?d3.scaleOrdinal().domain(series.map(d => d.key)).range(d3.schemeSpectral[series.length>4?series.length:4]).unknown("#ccc"):()=>d3.schemeSpectral[4][1]; +const color = props.datum.length>1?d3.scaleOrdinal().domain(series.map(d => d.key)).range(d3.schemeSpectral[series.length>4&&series.length<11?series.length:4]).unknown("#ccc"):()=>d3.schemeSpectral[4][1]; const rotation = options.value.width/(props.datum.map(props.axisX).filter(onlyUnique).length+1)<80?-10:0 const formatValue = x => isNaN(x) ? "N/A" : x.toLocaleString("en") onMounted(() => { diff --git a/front/components/core/AdviceList.vue b/front/components/core/AdviceList.vue index d20f9958..dd3986cd 100644 --- a/front/components/core/AdviceList.vue +++ b/front/components/core/AdviceList.vue @@ -1,6 +1,6 @@