Skip to content
Snippets Groups Projects
Commit cc56423e authored by Mohamed, Fawzi Roberto (fawzi)'s avatar Mohamed, Fawzi Roberto (fawzi)
Browse files

WIP html templates

parent 62a80cee
No related branches found
No related tags found
No related merge requests found
...@@ -36,7 +36,7 @@ function main() { ...@@ -36,7 +36,7 @@ function main() {
const stringify = require('json-stringify-safe'); const stringify = require('json-stringify-safe');
logger.info(`Started with arguments ${stringify(args)}`) logger.info(`Started with arguments ${stringify(args)}`)
logger.info(`Using configuration ${config.util.getEnv('NODE_ENV')} for instance ${process.env["NODE_APP_INSTANCE"]} ${stringify(config, null, 2)}`); logger.info(`Using configuration ${config.util.getEnv('NODE_ENV')} for instance ${process.env["NODE_APP_INSTANCE"]} ${stringify(config, null, 2)}`);
if (config.app.catchErrors) { if (config.app.catchErrors || config.app.debug) {
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
logger.error(`UncaughtException: ${stringify(err)}`) logger.error(`UncaughtException: ${stringify(err)}`)
}) })
......
...@@ -38,9 +38,11 @@ function guaranteeUserDir(userID, next) { ...@@ -38,9 +38,11 @@ function guaranteeUserDir(userID, next) {
/// functions that either gives the running pod or starts it /// functions that either gives the running pod or starts it
function getOrCreatePod(podName, repl, shouldCreate, next) { function getOrCreatePod(podName, repl, shouldCreate, next) {
logger.debug(`enter getOrCreatePod ${podName}`)
k8.ns(config.k8component.namespace).pod.get(podName, function(err, result) { k8.ns(config.k8component.namespace).pod.get(podName, function(err, result) {
if(err) { if(err) {
if (shouldCreate) { if (shouldCreate) {
logger.debug(`creating ${podName}`)
components.templateForImage(repl, function(err, template, repl) { components.templateForImage(repl, function(err, template, repl) {
if(err) { if(err) {
logger.error(`Cannot start pod ${podName}, error in template generation: ${stringify(err)}`); logger.error(`Cannot start pod ${podName}, error in template generation: ${stringify(err)}`);
...@@ -49,8 +51,9 @@ function getOrCreatePod(podName, repl, shouldCreate, next) { ...@@ -49,8 +51,9 @@ function getOrCreatePod(podName, repl, shouldCreate, next) {
guaranteeUserDir(repl.user, function (){ guaranteeUserDir(repl.user, function (){
const templateValue = yaml.safeLoad(template, 'utf8') const templateValue = yaml.safeLoad(template, 'utf8')
k8.ns(config.k8component.namespace).pod.post({ body: templateValue}, function(err, res2){ k8.ns(config.k8component.namespace).pod.post({ body: templateValue}, function(err, res2){
logger.debug(`created ${podName}`)
if(err) { if(err) {
logger.error(`Cannot start pod ${podName}, error: ${stringify(err)}, \n====\ntemplate was ${template}\n====\nexpanded to\n${templateValue}\n====`); logger.error(`Cannot start pod ${podName}, error: ${stringify(err)}, \n====\ntemplate was ${template}\n====\nconverted to\n${templateValue}\n====`);
next(err, null) next(err, null)
} else { } else {
logger.info(`Created pod ${podName}: ${stringify(res2)}`) logger.info(`Created pod ${podName}: ${stringify(res2)}`)
...@@ -73,8 +76,8 @@ function getOrCreatePod(podName, repl, shouldCreate, next) { ...@@ -73,8 +76,8 @@ function getOrCreatePod(podName, repl, shouldCreate, next) {
// cache pod name -> host & port // cache pod name -> host & port
const resolveCache = require('../safe-memory-cache/map.js')({ const resolveCache = require('../safe-memory-cache/map.js')({
limit: config.resolveCacheNMax, limit: config.app.resolveCacheNMax,
maxTTL: config.resolveCacheTtlMaxMs, maxTTL: config.app.resolveCacheTtlMaxMs,
refreshF: function(key, value, cache) { refreshF: function(key, value, cache) {
} }
}) })
...@@ -108,22 +111,28 @@ function resolvePod(repl, next) { ...@@ -108,22 +111,28 @@ function resolvePod(repl, next) {
resolveCache.set(podName, res) resolveCache.set(podName, res)
next(null, res) next(null, res)
} else { } else {
let secondsSinceCreation = (Date.parse(pod.metadata.creationTimestamp) - Date.now())/ 1000.0
const err = { const err = {
error: "not ready", error: "not ready",
msg: "pod not yet ready", msg: "pod not yet ready",
status: pod.status, status: pod.status,
host: podIp, host: podIp,
port: portNr port: portNr,
pod: pod,
secondsSinceCreation: secondsSinceCreation
} }
next(err, null) next(err, null)
} }
} else { } else {
let secondsSinceCreation = (Date.parse(pod.metadata.creationTimestamp) - Date.now())/ 1000.0
const err = { const err = {
error: "no ip", error: "no ip",
msg: "ip not yet available", msg: "ip not yet available",
status: pod.status, status: pod.status,
host: podIp, host: podIp,
port: portNr port: portNr,
pod: pod,
secondsSinceCreation: secondsSinceCreation
} }
next(err, null) next(err, null)
} }
...@@ -145,24 +154,40 @@ function resolvePod(repl, next) { ...@@ -145,24 +154,40 @@ function resolvePod(repl, next) {
ProxyRouter.prototype.lookup = function(req, res, userID, isWebsocket, path, next) { ProxyRouter.prototype.lookup = function(req, res, userID, isWebsocket, path, next) {
var start = Date.now() var start = Date.now()
components.cachedReplacements(req, function(err, repl) { components.cachedReplacements(req, function(err, repl) {
//logger.debug(`replacements available after ${(Date.now()-start)/1000.0}s`) logger.debug(`replacements available after ${(Date.now()-start)/1000.0}s`)
if (err) { if (err) {
logger.error(`No replacements: lookup without visiting the entry point ${config.k8component.entryPoint.path} (${stringify(err)})`) logger.error(`no replacements for ${userID} in %{path}`)
res.send(500, components.getHtmlErrorTemplate({
error:"No replacements",
msg: `lookup without visiting the entry point ${config.k8component.entryPoint.path} (${stringify(err)})`
}))
} else { } else {
resolvePod(repl, function (err, target) { resolvePod(repl, function (err, target) {
//logger.debug(`target available after ${(Date.now()-start)/1000.0}s`) logger.debug(`target available after ${(Date.now()-start)/1000.0}s, err: ${stringify(err)} target: ${stringify(target)}`)
if (err) { if (err) {
if (err.error === 'no ip' && err.status && err.status.phase === 'Pending' || if ((err.error === 'no ip' || err.error === 'not ready') &&
err.error === 'not ready') { err.status && err.status.phase === 'Pending') {
logger.warn(`pod ${repl.podName} ${err.error} ${stringify(err)}`) let error_detail = ''
res.send(reloadMsg) if (!err.secondsSinceCreation || err.secondsSinceCreation > 10)
error_detail = stringify(err, null, 2)
logger.debug(`eval reload`)
let repl = {
refreshEachS: config.app.pageReloadTime,
error_detail: error_detail
}
logger.debug(`repl done ${stringify(repl)}`)
components.evalHtmlTemplate(
'reloadMsg.html', repl,
function(err, pageHtml) {
res.send(pageHtml)
})
return;
} else { } else {
const errorMsg = `<html><head><title>Error starting Container!</title><meta http-equiv="refresh"<body><h3>Error ${err.error} while trying to start a container for you!</h3><p>${err.msg}</p><pre>${stringify(err, null, 2 )}</pre></body></html>`;
logger.error(`error starting container ${repl.podName}: ${stringify(err)}`) logger.error(`error starting container ${repl.podName}: ${stringify(err)}`)
res.send(500, errorMsg) res.send(500, components.getHtmlErrorTemplate(err, "Error starting container"))
} }
} else { } else {
// logger.debug(`Resolved to ${stringify(target)} after ${(Date.now()-start)/1000.0}s`) logger.debug(`Resolved to ${stringify(target)} after ${(Date.now()-start)/1000.0}s`)
next(target); next(target);
} }
}) })
......
...@@ -10,6 +10,7 @@ const url = require('url'); ...@@ -10,6 +10,7 @@ const url = require('url');
const compact_sha = require('./compact-sha') const compact_sha = require('./compact-sha')
const logger = require('./logger') const logger = require('./logger')
const stringify = require('json-stringify-safe') const stringify = require('json-stringify-safe')
const yaml = require('js-yaml')
var baseRepl = { var baseRepl = {
baseDir: baseDir, baseDir: baseDir,
...@@ -139,20 +140,37 @@ function getHtmlErrorTemplate(err, context = '') { ...@@ -139,20 +140,37 @@ function getHtmlErrorTemplate(err, context = '') {
// Helper to evaluate a web page template (layout + content) // Helper to evaluate a web page template (layout + content)
// will *always* give an html as result (it there was an error it describe the error // will *always* give an html as result (it there was an error it describe the error
function evalHtmlTemplate(htmlPath, repl, next, layout = null, context = '') { function evalHtmlTemplate(htmlPath, repl, next, { context = '' } = {} ) {
const layout = repl.layout || "defaultTemplate.html" logger.debug('entered evalHtmlTemplate')
evalTemplate("html/"+htmlPath, repl, function (err, template){ logger.debug(`entering evalHtmlTemplate(${stringify(htmlPath)}, ${stringify(repl)},...)`)
evalTemplate('html/'+htmlPath, repl, function (err, template){
logger.debug(`eval internal template err:${stringify(err)}, body:${stringify(template)}`)
if (err) { if (err) {
logger.debug(`returning error`)
next(err, getHtmlErrorTemplate(err, context)) next(err, getHtmlErrorTemplate(err, context))
} else { } else {
const repl2 = Object.assign({title: htmlPath, head: ''}, repl, { body: template }) let extraRepl = {}
evalHtmlTemplate("html/"+layout, repl2, function(err,res){ let templateBody = template
if (err) { let m = /\B---\B/.exec(template)
next(err, getHtmlErrorTemplate(err, context)) if (m) {
} else { templateBody = template.slice(m.index + 3)
next(nil, res) extraRepl = yaml.safeLoad(template.slice(0, m.index), 'utf8')
} }
}) logger.debug(`eval layout with extraRepl: ${stringify(extraRepl)} templateBody: ${stringify(templateBody)}`)
const repl2 = Object.assign({title: htmlPath, head: '', layout: "defaultLayout.html"}, extraRepl, repl, { body: templateBody })
const layout = repl2.layout
if (layout) {
evalTemplate("htmlLayout/"+layout, repl2, function(err,res){
logger.debug(`evaluated template, err: ${stringify(err)}`)
if (err) {
next(err, getHtmlErrorTemplate(err, context))
} else {
next(nil, res)
}
})
} else {
next(nil, templateBody)
}
} }
}) })
} }
...@@ -276,5 +294,7 @@ module.exports = { ...@@ -276,5 +294,7 @@ module.exports = {
cachedReplacements: cachedReplacements, cachedReplacements: cachedReplacements,
podNameForRepl: podNameForRepl, podNameForRepl: podNameForRepl,
infoForPodName: infoForPodName, infoForPodName: infoForPodName,
templateForImage: templateForImage templateForImage: templateForImage,
getHtmlErrorTemplate: getHtmlErrorTemplate,
evalHtmlTemplate: evalHtmlTemplate
} }
title: "Starting up!"
head: "<meta http-equiv=\"refresh\" content=\"{{refreshEachS}}\" >"
---
<h3>Please wait while we start a container for you!</h3> <h3>Please wait while we start a container for you!</h3>
<p>You might need to refresh manually (F5)...</p>p> <p>You might need to refresh manually (F5)...</p>p>
<pre>
{{error_detail}}
</pre>
...@@ -11,6 +11,7 @@ metadata: ...@@ -11,6 +11,7 @@ metadata:
spec: spec:
imagePullSecrets: imagePullSecrets:
- name: garching-kube - name: garching-kube
restartPolicy: Never
containers: containers:
- image: "{{image}}" - image: "{{image}}"
name: "{{imageType}}" name: "{{imageType}}"
......
...@@ -4,6 +4,7 @@ metadata: ...@@ -4,6 +4,7 @@ metadata:
name: {{podName}} name: {{podName}}
spec: spec:
terminationGracePeriodSeconds: 5 terminationGracePeriodSeconds: 5
restartPolicy: Never
containers: containers:
- image: labdev-nomad.esc.rzg.mpg.de:5000/nomadlab/nomadvis:v1.0.7 - image: labdev-nomad.esc.rzg.mpg.de:5000/nomadlab/nomadvis:v1.0.7
name: nomadvis name: nomadvis
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment