diff --git a/slapos/recipe/kvm_frontend/__init__.py b/slapos/recipe/kvm_frontend/__init__.py index 4af57a00b3ac56b424fb59fc33bebfe5b4e132b0..a14476ebee91b1c54a2b0de449d6356a8ad31225 100644 --- a/slapos/recipe/kvm_frontend/__init__.py +++ b/slapos/recipe/kvm_frontend/__init__.py @@ -254,15 +254,29 @@ class Recipe(BaseSlapRecipe): def installFrontendNode(self, ip, port, key, certificate, plain_http, name, rewrite_rule_list): + # Create Map map_name = "proxy_table.json" map_content = self._getProxyTableContent(rewrite_rule_list) map_file = self.createConfigurationFile(map_name, map_content) - self.path_list.append(map_file) + + # Install script + kvm_proxy_script_in = pkg_resources.resource_filename( + __name__, os.path.join('template', 'kvm-proxy.js')) + kvm_proxy_script = self.createRunningWrapper("kvm-proxy.js", + kvm_proxy_script_in) + self.path_list.append(kvm_proxy_script) + + # Get environment + self.options['node-path'] + + # Create wrapper wrapper = zc.buildout.easy_install.scripts([( - name, 'slapos.recipe.librecipe.execute', 'execute')], self.ws, + name, 'slapos.recipe.librecipe.execute', 'executee_wait')], self.ws, sys.executable, self.wrapper_directory, arguments=[ - ip, port, key, certificate, plain_http] + self.options['dcrond_binary'].strip(), kvm_proxy_script, + ip, port, key, certificate, plain_http], + {'NODE_PATH': self.options['node-path']} )[0] self.path_list.extend(wrapper) diff --git a/slapos/recipe/kvm_frontend/template/kvm-proxy.js b/slapos/recipe/kvm_frontend/template/kvm-proxy.js new file mode 100644 index 0000000000000000000000000000000000000000..39ad65c7cc1f34b58dc693133ce093089ba9621c --- /dev/null +++ b/slapos/recipe/kvm_frontend/template/kvm-proxy.js @@ -0,0 +1,114 @@ +var fs = require('fs'), + util = require('util'), + colors = require('colors'), + http = require('http'), + httpProxy = require('http-proxy'), + process = require('process') + proxyByUrl = require('proxy-by-url'); + +var proxyTable = 'proxy-table.json', + //listenInterface = '2a01:e34:ec03:8610:60c:ceff:fed1:b9fc', + listenInterface = process.argv[1], + port = process.argv[2], + sslKeyFile = process.argv[3], + sslCertFile = process.argv[4], + redirect = process.argv[5] || false, + isRawIPv6; + +isRawIPv6 = function checkipv6(str) { + // Inspired by http://forums.intermapper.com/viewtopic.php?t=452 + return (/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(str)); +}(listenInterface); + +// Dummy middleware that throws 404 not found. +var middlewareNotFound = function(req, res, proxy) { + res.statusCode = 404; + res.setHeader('Content-Type', 'text/plain'); + res.end('This URL is not known. Please check your URL or contact your ' + + 'SlapOS administrator.'); +}; +middlewareNotFound.proxyWebSocketRequest = function(req, socket, head, next) { + console.log('stop'); + socket.end(); +}; + +/** + * Rewrite URL to match Zope's virtual host monster if we use vifib + */ +var middlewareVifib = function(req, res, next) { + // Completely hardcoded rewrite + var vifibPrefix = '/hosting'; + if (req.url.indexOf(vifibPrefix) == 0) { + var hostname = 'localhost', + port = '8000'; + // Rewrite URL to match virtual host + req.url = vifibPrefix + '/VirtualHostBase/https/' + hostname + ':' + port + + '/erp5/web_site_module/VirtualHostRoot' + req.url; + console.log('Vifib rewrite. New URL is : ' + req.url); + } + next(); +}; + +/** + * Create server + */ +var proxyServer = httpProxy.createServer( + middlewareVifib, + // We declare our proxyByUrl middleware + proxyByUrl(proxyTable), + // Then we add your dummy middleware, called when proxyByUrl doesn't find url. + middlewareNotFound, + // And we set HTTPS options for server. HTTP will be forbidden. + { + https: { + key: fs.readFileSync( + //'/Users/cedricdesaintmartin/Desktop/SlapOS/slapconsole-keys/cedric-owf-0/ssl.key', + sslKeyFile, + 'utf8' + ), + cert: fs.readFileSync( + //'/Users/cedricdesaintmartin/Desktop/SlapOS/slapconsole-keys/cedric-owf-0/ssl.cert', + sslCertFile, + 'utf8' + ) + }, + source: { + host: listenInterface, + port: port + }} +); + +// We gonna rock this civilization. +proxyServer.listen(port, listenInterface); +console.log('HTTPS server started and listening at ' + listenInterface + ':' + + port); + +// Dummy HTTP server redirecting to HTTPS. Only has sense if we can use port 80 +if (redirect === true) { + try { + var httpPort = 80; + http.createServer(function(req, res) { + var url; + if (isRawIPv6 === true) { + url = 'https://[' + listenInterface + ']'; + } else { + url = 'https://' + listenInterface; + } + // If non standard port : need to specify it + if (port !== 443) { + url = url + ':' + port; + } + // Add last part of URL + url = url + req.url; + console.log(url); + // Anwser "permanently redirected" + res.statusCode = 301; + res.setHeader('Location', url); + res.end(); + }).listen(httpPort, listenInterface); + console.log('HTTP redirect server started and listening at ' + + listenInterface + ':' + httpPort); + } catch (EACCES) { + console.log('Couldn\'t start plain HTTP redirection server : ' + EACCESS) + } +}