Skip to content

Commit

Permalink
fix: add dep tree plantuml
Browse files Browse the repository at this point in the history
  • Loading branch information
devthejo committed Jun 2, 2022
1 parent cb2333b commit fe35b2c
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 203 deletions.
8 changes: 8 additions & 0 deletions packages/common/utils/stream-to-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = (stream) => {
const chunks = []
return new Promise((resolve, reject) => {
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)))
stream.on("error", (err) => reject(err))
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")))
})
}
1 change: 1 addition & 0 deletions packages/kontinuous/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"lodash.defaultsdeep": "^4.6.1",
"lodash.mergewith": "^4.6.2",
"nctx": "^1.2.0",
"node-plantuml": "^0.9.0",
"pino": "^7.10.0",
"pino-pretty": "^7.6.0",
"pretty-ms": "^7.0.1",
Expand Down
207 changes: 207 additions & 0 deletions packages/kontinuous/src/build/infos/component-tree-infos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// const fs = require("fs-extra")

const ctx = require("~/ctx")
const logTree = require("~common/utils/log-tree")

const getTreeInfos = {}

getTreeInfos.Namespace = (resource) => {
const { manifest } = resource
return [{ name: `name: ${manifest.metadata.name}`}]
}

getTreeInfos.Ingress = (resource)=>{
const { manifest } = resource
const redirect = manifest.metadata?.annotations["nginx.ingress.kubernetes.io/permanent-redirect"]
return [...(manifest.spec?.rules ? [{
name: "hosts",
children: manifest.spec.rules.map(({host})=>({name:`https://${host}`}))
}] : []), ...(redirect ? [{
name: "redirect",
children: [{name: redirect}]
}] : [])]
}

getTreeInfos.Deployment = (resource) => {
const { manifest } = resource
const containers = manifest.spec?.template?.spec?.containers
const initContainers = manifest.spec?.template?.spec?.initContainers
return [...(containers ? containers.map(container=>{
return {name:container.name, children: [
{
name: `image: ${container.image}`,
},
{
name: `port${container.ports.length>1?"s":""}: ${container.ports.map(({ containerPort }) => containerPort).join(",")}`,
},
]}}) : []),
...(initContainers ? initContainers.map(container=>{
return {name: `${container.name} (init)`, children: [
{
name: `image: ${container.image}`,
},
]}}) : []),
]
}

getTreeInfos.Service = (resource) => {
const { manifest } = resource
const ports = manifest.spec.ports
const children = []
if(ports){
const portStr = ports.map(port=> `${port.name ? port.name + "=" : ""}${port.port}:${port.targetPort}`)
children.push({
name: `port${ports.length > 1 ? "s" : ""}: ${portStr}`
})
}
return children
}

getTreeInfos.ConfigMap = (resource) => {
const { manifest } = resource
return [{ name: `name: ${manifest.metadata.name}` }]
}

getTreeInfos.SealedSecret = (resource) => {
const { manifest } = resource
return [{ name: `name: ${manifest.metadata.name}` }]
}

getTreeInfos.Job = (resource) => {
const { manifest } = resource
const containers = manifest.spec?.template?.spec?.containers
const initContainers = manifest.spec?.template?.spec?.initContainers
return [...(containers ? containers.map(container => {
return {
name: container.name, children: [
{
name: `image: ${container.image}`,
},
]
}
}) : []),
...(initContainers ? initContainers.map(container => {
return {
name: `${container.name} (init)`, children: [
{
name: `image: ${container.image}`,
},
]
}
}) : []),
]
}

getTreeInfos.CronJob = (resource) => {
const { manifest } = resource
const containers = manifest.spec?.jobTemplate?.spec?.template?.spec?.containers
const initContainers = manifest.spec?.jobTemplate?.spec?.template?.spec?.initContainers
return [
{ name: `schedule: ${manifest.spec.schedule}` },
...(containers ? containers.map(container => {
return {
name: container.name, children: [
{
name: `image: ${container.image}`,
},
]
}
}) : []),
...(initContainers ? initContainers.map(container => {
return {
name: `${container.name} (init)`, children: [
{
name: `image: ${container.image}`,
},
]
}
}) : []),
]
}


module.exports = async(manifests)=>{
const logger = ctx.require("logger")
const config = ctx.require("config")
const {
buildPath,
} = config

const componentResources = {}
const globalResources = {kinds: {}}
for (let manifest of manifests) {
if (!manifest.metadata?.labels?.component) {
if (!globalResources.kinds[manifest.kind]) {
globalResources.kinds[manifest.kind] = []
}
globalResources.kinds[manifest.kind].push({
name: manifest.metadata?.name,
manifest,
})
} else {
const { component } = manifest.metadata.labels
if (!componentResources[component]){
componentResources[component] = {
kinds: {}
}
}
if (!componentResources[component].kinds[manifest.kind]){
componentResources[component].kinds[manifest.kind] = []
}
componentResources[component].kinds[manifest.kind].push({
name: manifest.metadata?.name,
manifest,
})
}
}
const componentsTree = []
for (const [name, component] of Object.entries(componentResources)){
const resources = []
for (const [kind, kindResources] of Object.entries(component.kinds)){
const children = []
for (const resource of kindResources){
if (getTreeInfos[kind]){
children.push(...getTreeInfos[kind](resource))
}
}
resources.push({
name: `${kind}`,
children,
})
}
componentsTree.push({
name,
children: resources,
})
}

const globalsTree = []
for (const [kind, kindResources] of Object.entries(globalResources.kinds)) {
const children = []
for (const resource of kindResources) {
if (getTreeInfos[kind]) {
children.push(...getTreeInfos[kind](resource))
}
}
globalsTree.push({
name: `${kind}`,
children,
})
}
const tree = [
{
name: "components",
children: componentsTree
},
{
name: "globals",
children: globalsTree,
},
]

const treeStr = logTree(tree)
logger.debug("\n"+treeStr)

// await fs.writeFile(`${buildPath}/manifests.tree.md`, `\`\`\`\n${treeStr}\n\`\`\``)

}
67 changes: 67 additions & 0 deletions packages/kontinuous/src/build/infos/dependencies-tree-infos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// const fs = require("fs-extra")
const plantuml = require("node-plantuml")
const camelcase = require("lodash.camelcase")
const ctx = require("~/ctx")

const streamToString = require("~common/utils/stream-to-string")

const changeGroupPrefix = "kapp.k14s.io/change-group"
const changeRulePrefix = "kapp.k14s.io/change-rule"
const changeRuleValuePrefix = "upsert after upserting kontinuous/"

module.exports = async(manifests)=>{
const logger = ctx.require("logger")
// const config = ctx.require("config")

const flatDependencies = {}

for (const manifest of manifests) {
const annotations = manifest.metadata?.annotations
if (!annotations || !annotations[changeGroupPrefix]) {
continue
}
const depKey = Object.keys(annotations)
.find(key => key.startsWith(`${changeGroupPrefix}.`))
.split(".").pop()

for (const [key, value] of Object.entries(annotations)) {
if (
(key === changeRulePrefix ||
key.startsWith(`${changeRulePrefix}.`))
&& value.startsWith(changeRuleValuePrefix)
) {
if(!flatDependencies[depKey]){
flatDependencies[depKey] = new Set()
}
let dep = value.slice(changeRuleValuePrefix.length)
dep = dep.split(".").shift()
dep = camelcase(dep)
flatDependencies[depKey].add(dep)
}
}
}


const uml = []
for(const [key, dependenciesSet] of Object.entries(flatDependencies)){
for(const dep of dependenciesSet){
if(dep!==key){
uml.push(`${dep} -> ${key}`)
}
}
}

if(uml.length===0){
return
}

const gen = plantuml.generate(uml.join("\n"), {
format: "ascii"
});
const result = await streamToString(gen.out)
logger.debug("\n"+result)

// await fs.writeFile(`${config.buildPath}/dependencies.tree.md`, `uml\`\`\`\n${result}\n\`\`\``)


}
Loading

0 comments on commit fe35b2c

Please sign in to comment.