From 5f7f8803a571dd1f927bbc108c4c3ddb60d814b2 Mon Sep 17 00:00:00 2001 From: pbochynski Date: Wed, 22 Nov 2023 09:33:51 +0100 Subject: [PATCH] Manageable modules --- app/app.js | 83 ++++++++++++++++++++++++-------------- app/kyma.html | 2 +- app/modules.json | 9 +++++ script/release-channels.js | 4 +- 4 files changed, 65 insertions(+), 33 deletions(-) diff --git a/app/app.js b/app/app.js index 294e3de..bbb8716 100644 --- a/app/app.js +++ b/app/app.js @@ -15,7 +15,7 @@ var modules = [] async function apply(res) { let path = await resPath(res) path += '?fieldManager=kubectl&fieldValidation=Strict&force=false' - let response = await fetch(API_PREFIX+path, { method: 'PATCH', headers: { 'content-type': 'application/apply-patch+yaml' }, body: JSON.stringify(res) }) + let response = await fetch(API_PREFIX + path, { method: 'PATCH', headers: { 'content-type': 'application/apply-patch+yaml' }, body: JSON.stringify(res) }) return response } function channelDropdown() { @@ -62,13 +62,13 @@ function channelDropdown() { div.appendChild(ul) div.appendChild(updateBtn) - if (API_PREFIX!='') { + if (API_PREFIX != '') { let busolaBtn = document.createElement('button') busolaBtn.setAttribute('class', 'btn btn-outline-primary btn-sm') busolaBtn.setAttribute('type', 'button') busolaBtn.textContent = 'Kyma Dashboard' busolaBtn.addEventListener('click', openBusola) - div.appendChild(busolaBtn) + div.appendChild(busolaBtn) } return div @@ -81,12 +81,12 @@ async function applyModule(m) { await apply(m.cr.resource) } function openBusola() { - localStorage.setItem('busola.clusters','{"kyma":{"name":"kyma","kubeconfig":{"apiVersion":"v1","clusters":[{"cluster":{"server":"http://127.0.0.1:8001/backend"},"name":"kyma"}],"contexts":[{"context":{"cluster":"kyma","user":"admin"},"name":"kyma"}],"current-context":"kyma","kind":"Config","preferences":{},"users":[{"name":"admin","user":{"token":"tokentokentoken"}}]},"contextName":"kyma","config":{"storage":"localStorage"},"currentContext":{"cluster":{"cluster":{"server":"http://127.0.0.1:8001/backend"},"name":"kyma"},"user":{"name":"admin","user":{"token":"tokentokentoken"}}}}}') - window.open('/index.html','_blank') + localStorage.setItem('busola.clusters', '{"kyma":{"name":"kyma","kubeconfig":{"apiVersion":"v1","clusters":[{"cluster":{"server":"http://127.0.0.1:8001/backend"},"name":"kyma"}],"contexts":[{"context":{"cluster":"kyma","user":"admin"},"name":"kyma"}],"current-context":"kyma","kind":"Config","preferences":{},"users":[{"name":"admin","user":{"token":"tokentokentoken"}}]},"contextName":"kyma","config":{"storage":"localStorage"},"currentContext":{"cluster":{"cluster":{"server":"http://127.0.0.1:8001/backend"},"name":"kyma"},"user":{"name":"admin","user":{"token":"tokentokentoken"}}}}}') + window.open('/index.html', '_blank') } function get(path) { - return fetch(API_PREFIX+path).then((res) => { + return fetch(API_PREFIX + path).then((res) => { if (res.status == 200) { return res.json() } @@ -98,7 +98,7 @@ function deleteModuleResources(m) { if (r.path == '/api/v1/namespaces/kyma-system') { continue; // skip kyma-system deletion } - fetch(API_PREFIX+r.path, { method: 'DELETE' }) + fetch(API_PREFIX + r.path, { method: 'DELETE' }) } } async function removeModuleFromKymaCR(name) { @@ -107,12 +107,21 @@ async function removeModuleFromKymaCR(name) { for (let i = 0; i < kyma.spec.modules.length; ++i) { if (kyma.spec.modules[i].name == name) { let body = `[{"op":"remove","path":"/spec/modules/${i}"}]` - fetch(API_PREFIX+KYMA_PATH, { method: 'PATCH', headers: { 'content-type': 'application/json-patch+json' }, body }) + fetch(API_PREFIX + KYMA_PATH, { method: 'PATCH', headers: { 'content-type': 'application/json-patch+json' }, body }) return } } } } +async function addModuleToKymaCR(name) { + let kyma = await get(KYMA_PATH) + if (kyma && kyma.spec.modules) { + let body = `[{"op":"add","path":"/spec/modules/-","value":{"name":"${name}"}}]` + fetch(API_PREFIX + KYMA_PATH, { method: 'PATCH', headers: { 'content-type': 'application/json-patch+json' }, body }) + return + } +} + async function deleteModule(m) { if (m.managed) { modal("This is a managed module. Do you want to remove it from SKR managed resources?", "Delete confirmation", async () => { @@ -128,7 +137,7 @@ async function deleteModule(m) { modal(body, "Delete confirmation", async () => { for (let i = 0; i < 5 && toDelete.length > 0; ++i) { for (let i of toDelete) { - fetch(API_PREFIX+i, { method: 'DELETE' }) + fetch(API_PREFIX + i, { method: 'DELETE' }) } toDelete = await managedResourcesList(m) setTimeout(() => checkStatus(), 1000) @@ -235,13 +244,13 @@ async function exists(path) { if (!path) { return false; } - let response = await fetch(API_PREFIX+path) + let response = await fetch(API_PREFIX + path) return (response.status == 200) } async function cacheAPI(apiVersion) { let url = (apiVersion === 'v1') ? '/api/v1' : `/apis/${apiVersion}` - let res = await fetch(API_PREFIX+url) + let res = await fetch(API_PREFIX + url) if (res.status == 200) { let body = await res.json() groupVersions[apiVersion] = body @@ -259,7 +268,7 @@ function deploymentList(m) { if (r.status === true) { badge = `applied` html += `
  • - + ${r.resource.kind}: ${r.resource.metadata.name} ${badge}
  • ` } else { html += `
  • ${r.resource.kind}: ${r.resource.metadata.name} ${badge}
  • ` @@ -308,6 +317,16 @@ function applyBtn(m) { }) return btn } +function addBtn(m) { + let btn = document.createElement("button") + btn.textContent = "add" + btn.setAttribute('class', 'btn btn-outline-primary btn-sm') + btn.addEventListener("click", function (event) { + addModuleToKymaCR(m.name) + setTimeout(() => checkStatus(), 3000) + }) + return btn +} function detailsBtn(m) { let btn = document.createElement("button") @@ -329,17 +348,17 @@ function deleteBtn(m) { }) return btn } -function externalLink(href,name) { +function externalLink(href, name) { if (href) { return ` - ${name} ` + ${name} ` } return "" } function configLink(m) { if (m.cr.status) { - return ` - configuration ` + return ` + configuration ` } return "configuration" } @@ -347,6 +366,9 @@ function configLink(m) { function moduleCard(m) { let buttons = document.createElement("div") buttons.setAttribute('class', 'd-inline-flex gap-1') + if (m.manageable && !m.managed) { + buttons.appendChild(addBtn(m)) + } if (!m.managed && m.deploymentYaml) { buttons.appendChild(applyBtn(m)) } @@ -361,7 +383,7 @@ function moduleCard(m) { let txt = document.createElement("div") let version = "-" if (m.deploymentVersion) { - version=m.deploymentVersion.split('/')[m.deploymentVersion.split('/').length - 1] + version = m.deploymentVersion.split('/')[m.deploymentVersion.split('/').length - 1] } let html = `
    ${m.name} ${moduleBadge(m)}
    @@ -369,8 +391,8 @@ function moduleCard(m) { deployment: ${resourcesBadge(m)}
    ${version} ${versionBadge(m)} ${availableBadge(m)}
    ${configLink(m)} ${crBadge(m)}
    - ${externalLink(m.documentation,"docs")} - ${externalLink(m.repository,"repo")} + ${externalLink(m.documentation, "docs")} + ${externalLink(m.repository, "repo")}
    ` txt.innerHTML = html @@ -417,17 +439,16 @@ function availableBadge(m) { async function managedModules() { let kyma = await get(KYMA_PATH) if (kyma) { - for (let m of modules) { - if (m.name == 'istio') { - m.managed = true - continue; - } if (kyma.spec.modules) { let mm = kyma.spec.modules.find((mod) => mod.name == m.name) m.managed = (mm) ? true : false } } + } else { + for (let m of modules) { + m.manageable = false + } } } @@ -455,7 +476,7 @@ function checkStatus() { for (let m of modules) { resPath(m.cr.resource).then((p) => { m.cr.path = p - return (p) ? fetch(API_PREFIX+p) : null + return (p) ? fetch(API_PREFIX + p) : null }).then((res) => { if (res) { m.cr.status = (res.status == 200) @@ -472,7 +493,7 @@ function checkStatus() { m.available = false m.actualVersion = undefined if (r.path) { - fetch(API_PREFIX+r.path).then((res) => { + fetch(API_PREFIX + r.path).then((res) => { if (res.status == 200) { r.status = true return res.json() @@ -484,13 +505,13 @@ function checkStatus() { }).then((json) => { r.value = json if (json && json.kind == 'Deployment') { - if (json.spec.template.spec.containers.length==1) { + if (json.spec.template.spec.containers.length == 1) { m.actualVersion = json.spec.template.spec.containers[0].image } else { - for (let c of json.spec.template.spec.containers){ - if (!c.image.indexOf('proxy')>=0) { + for (let c of json.spec.template.spec.containers) { + if (!c.image.indexOf('proxy') >= 0) { m.actualVersion = c.image - } + } } } console.log(m.actualVersion, json.status) @@ -511,7 +532,7 @@ function checkStatus() { } function getPods() { - fetch(API_PREFIX+'/api/v1/pods') + fetch(API_PREFIX + '/api/v1/pods') .then((response) => response.json()) .then((podList) => { pods = podList.items.sort((a, b) => { diff --git a/app/kyma.html b/app/kyma.html index f658fa4..932d4ae 100644 --- a/app/kyma.html +++ b/app/kyma.html @@ -14,7 +14,7 @@
    diff --git a/app/modules.json b/app/modules.json index a0b6ff2..8fa6bd0 100644 --- a/app/modules.json +++ b/app/modules.json @@ -33,6 +33,7 @@ "/apis/security.istio.io/v1beta1/requestauthentications", "/apis/telemetry.istio.io/v1alpha1/telemetries" ], + "manageable": true, "versions": [ { "version": "latest", @@ -79,6 +80,7 @@ "/apis/serverless.kyma-project.io/v1alpha2/functions", "/apis/operator.kyma-project.io/v1alpha1/serverlesses" ], + "manageable": true, "versions": [ { "version": "latest", @@ -110,6 +112,7 @@ "/apis/services.cloud.sap.com/v1alpha1/serviceinstances", "/apis/operator.kyma-project.io/v1alpha1/btpoperators" ], + "manageable": true, "versions": [ { "version": "latest", @@ -140,6 +143,7 @@ "/apis/telemetry.kyma-project.io/v1alpha1/logpipelines", "/apis/telemetry.kyma-project.io/v1alpha1/tracepipelines" ], + "manageable": true, "versions": [ { "version": "latest", @@ -168,6 +172,7 @@ "managedResources": [ "/apis/operator.kyma-project.io/v1alpha1/nats" ], + "manageable": true, "versions": [ { "version": "latest", @@ -188,6 +193,7 @@ "crYaml": "https://github.com/kyma-project/eventing-manager/releases/latest/download/eventing_default_cr.yaml", "documentation": "https://kyma-project.io/#/eventing-manager/user/README", "repository": "https://github.com/kyma-project/eventing-manager.git", + "manageable": true, "managedResources": [ "/apis/eventing.kyma-project.io/v1alpha1/subscriptions", "/apis/eventing.kyma-project.io/v1alpha2/subscriptions", @@ -213,6 +219,7 @@ "crYaml": "https://github.com/kyma-project/application-connector-manager/releases/latest/download/default_application_connector_cr.yaml", "documentation": "https://kyma-project.io/#/application-connector-manager/user/README", "repository": "https://github.com/kyma-project/application-connector-manager.git", + "manageable": true, "managedResources": [ "/apis/operator.kyma-project.io/v1alpha1/applicationconnectors" ], @@ -243,6 +250,7 @@ "/apis/keda.sh/v1alpha1/scaledobjects", "/apis/keda.sh/v1alpha1/triggerauthentications" ], + "manageable": true, "versions": [ { "version": "latest", @@ -263,6 +271,7 @@ "managedResources": [ "apis/operator.kyma-project.io/v1alpha1/transparentproxies" ], + "manageable": true, "cr": { "resource": { "apiVersion": "operator.kyma-project.io/v1alpha1", diff --git a/script/release-channels.js b/script/release-channels.js index f3b4784..ce158e6 100644 --- a/script/release-channels.js +++ b/script/release-channels.js @@ -35,7 +35,9 @@ async function loadModule(m) { async function releaseChannels() { for (let ch of channels) { + console.log("processing channel:", ch.name) for (let mod of ch.modules) { + console.log(" -", mod.name) for (let m of modules) { if (m.name == mod.name) { mod.deploymentYaml = m.deploymentYaml @@ -46,6 +48,7 @@ async function releaseChannels() { mod.resources = m.resources mod.cr = m.cr mod.community = m.community + mod.manageable = m.manageable for (let v of m.versions) { if (mod.version == v.version) { if (v.managedResources) { @@ -75,7 +78,6 @@ async function releaseChannels() { } await loadModule(mod) } - console.log("channel loaded:", ch.name) fs.writeFileSync(`${ch.name}.json`, JSON.stringify(ch.modules, null, 2)) console.log("channel written:", `${ch.name}.json`) }