diff --git a/cgi-bin/diff.py b/cgi-bin/diff.py index e5ede821..bff1a694 100644 --- a/cgi-bin/diff.py +++ b/cgi-bin/diff.py @@ -64,11 +64,8 @@ if form.getvalue('serv') is not None and form.getvalue('open') is not None : print('') print('' % serv) print('') - print('

') + print('Show

') -if form.getvalue('serv') is not None and form.getvalue('right') is not None: - commands = [ 'diff -ub %s%s %s%s' % (hap_configs_dir, left, hap_configs_dir, right) ] - funct.ssh_command(haproxy_configs_server, commands, compare="1") funct.footer() \ No newline at end of file diff --git a/cgi-bin/edit.py b/cgi-bin/edit.py index d8a992f5..b2c9d71a 100644 --- a/cgi-bin/edit.py +++ b/cgi-bin/edit.py @@ -1,63 +1,15 @@ #!/usr/bin/env python3 import html import cgi -import listserv as listhap -import subprocess -import os -import http.cookies import funct -import configparser -from funct import head as head form = cgi.FieldStorage() serv = form.getvalue('serv') -action = form.getvalue('servaction') -backend = form.getvalue('servbackend') - -head("Runtime API") +funct.head("Runtime API") funct.check_login() funct.check_config() -path_config = "haproxy-webintarface.config" -config = configparser.ConfigParser() -config.read(path_config) - -server_state_file = config.get('haproxy', 'server_state_file') -haproxy_sock = config.get('haproxy', 'haproxy_sock') - -if backend is None: - backend = "" - autofocus = "" -else: - autofocus = "autofocus" - -if action == 'disable': - selected1 = 'selected' - selected2 = '' - selected3 = '' - selected4 = '' -elif action == 'enable': - selected1 = '' - selected2 = 'selected' - selected3 = '' - selected4 = '' -elif action == 'set': - selected1 = '' - selected2 = '' - selected3 = 'selected' - selected4 = '' -elif action == 'show': - selected1 = '' - selected2 = '' - selected3 = '' - selected4 = 'selected' -else: - selected1 = '' - selected2 = '' - selected3 = '' - selected4 = '' - print('

Runtime API

' '' '' @@ -70,45 +22,30 @@ print('

Runtime API

' '' '' '') -print('' - '
' '
' - '' '') funct.choose_server_with_vip(serv) print('
' - '' '') if funct.is_admin(): - print('' % selected1) - print('' % selected2) - print('' % selected3) -print('' % selected4) -print('' % (backend, autofocus)) - -print('' - '' - '') -funct.get_button("Enter") -print('
') - -if form.getvalue('servaction') is not None: - enable = form.getvalue('servaction') - cmd='echo "%s %s" |socat stdio %s | cut -d "," -f 1-2,5-10,34-36 | column -s, -t' % (enable, backend, haproxy_sock) - - if form.getvalue('save') == "on": - save_command = 'echo "show servers state" | socat stdio %s > %s' % (haproxy_sock, server_state_file) - command = [ cmd, save_command ] - else: - command = [ cmd ] - - if enable != "show": - print('

You %s %s on HAproxy %s. Look it or Edit something else


' % (enable, backend, serv, serv)) - - funct.ssh_command(serv, command, show_log="1") - action = 'edit.py ' + enable + ' ' + backend - funct.logging(serv, action) + print('') + print('') + print('') +print('' + '' + '' + '' + '' + '' + '' + 'Show' + '' + '' + '
' + '
') funct.footer() \ No newline at end of file diff --git a/cgi-bin/funct.py b/cgi-bin/funct.py index 593156f5..928501ee 100644 --- a/cgi-bin/funct.py +++ b/cgi-bin/funct.py @@ -22,6 +22,8 @@ path_config = "haproxy-webintarface.config" config = configparser.ConfigParser() config.read(path_config) +form = cgi.FieldStorage() +serv = form.getvalue('serv') fullpath = config.get('main', 'fullpath') ssh_keys = config.get('ssh', 'ssh_keys') ssh_user_name = config.get('ssh', 'ssh_user_name') @@ -121,11 +123,13 @@ def head(title): '' '' '' + '' '' '' '' '' '' + '' '' '' '' @@ -140,7 +144,7 @@ def head(title): '
' '
' 'HAproxy-WI' - '' + '' '' '' '' @@ -186,7 +190,7 @@ def links(): show_login_links() print('' '' - '') + '') def show_login_links(): cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) @@ -546,16 +550,14 @@ def choose_only_select(serv, **kwargs): print('' % (listhap.get(i), selected, i)) def chooseServer(formName, title, note): + servNew = form.getvalue('serNew') + print('

' + title + '

') print('

Choose server

') print('
') - print('

') print('') - form = cgi.FieldStorage() - serv = form.getvalue('serv') - servNew = form.getvalue('serNew') - choose_only_select(serv, servNew=servNew) print('') diff --git a/cgi-bin/logs.py b/cgi-bin/logs.py index b4824e3b..830b6924 100644 --- a/cgi-bin/logs.py +++ b/cgi-bin/logs.py @@ -2,8 +2,6 @@ import html import cgi import listserv as listhap -import subprocess -import os import funct import configparser @@ -47,20 +45,13 @@ else: grep = ' ' print('' % rows) -print('' % grep) +print('' % grep) print('' - '' - '' - 'Show') -if form.getvalue('serv') is not None: - print('' - '' - 'Update' - '' - '') -print('' - '

' - '' + '' + 'Show' + '' + '' + '' '
' '
') funct.footer() \ No newline at end of file diff --git a/cgi-bin/options.py b/cgi-bin/options.py index 4d1ae4d0..2a4d71d6 100644 --- a/cgi-bin/options.py +++ b/cgi-bin/options.py @@ -11,6 +11,7 @@ options = [ "acl", "http-request", "http-response", "set-uri", "set-url", "set-h path_config = "haproxy-webintarface.config" config = configparser.ConfigParser() config.read(path_config) +funct.check_config() form = cgi.FieldStorage() req = form.getvalue('req') @@ -121,6 +122,34 @@ if serv is not None and form.getvalue('act') is not None: if form.getvalue('act') == "overview": import ovw ovw.get_overview() + +if form.getvalue('servaction') is not None: + server_state_file = config.get('haproxy', 'server_state_file') + haproxy_sock = config.get('haproxy', 'haproxy_sock') + enable = form.getvalue('servaction') + cmd='echo "%s %s" |socat stdio %s | cut -d "," -f 1-2,5-10,34-36 | column -s, -t' % (enable, backend, haproxy_sock) + + if form.getvalue('save') == "on": + save_command = 'echo "show servers state" | socat stdio %s > %s' % (haproxy_sock, server_state_file) + command = [ cmd, save_command ] + else: + command = [ cmd ] + + if enable != "show": + print('

You %s %s on HAproxy %s. Look it or Edit something else


' % (enable, backend, serv, serv)) + + funct.ssh_command(serv, command, show_log="1") + action = 'edit.py ' + enable + ' ' + backend + funct.logging(serv, action) + +if serv is not None and form.getvalue('right') is not None: + left = form.getvalue('left') + right = form.getvalue('right') + haproxy_configs_server = config.get('configs', 'haproxy_configs_server') + hap_configs_dir = config.get('configs', 'haproxy_save_configs_dir') + commands = [ 'diff -ub %s%s %s%s' % (hap_configs_dir, left, hap_configs_dir, right) ] + + funct.ssh_command(haproxy_configs_server, commands, compare="1") if form.getvalue('tailf_stop') is not None: serv = form.getvalue('serv') diff --git a/cgi-bin/ovw.py b/cgi-bin/ovw.py index d08f9012..e3c38e56 100644 --- a/cgi-bin/ovw.py +++ b/cgi-bin/ovw.py @@ -59,11 +59,6 @@ def get_overview(): '' 'Last edit' '' - '' - '' - 'Update' - '' - '' '') listhap = funct.get_dick_after_permit() @@ -94,11 +89,6 @@ def get_overview(): '' '' 'Server status' - '' - '' - 'Update' - '' - '' '' '') print('') diff --git a/cgi-bin/viewsttats.py b/cgi-bin/viewsttats.py index 85455729..4695abd9 100644 --- a/cgi-bin/viewsttats.py +++ b/cgi-bin/viewsttats.py @@ -57,9 +57,8 @@ print('
' funct.choose_server_with_vip(serv) -print('' - '' - 'Show' +print('' + 'Show' '') data = response.content diff --git a/inc/nprogress.css b/inc/nprogress.css new file mode 100644 index 00000000..ef766b86 --- /dev/null +++ b/inc/nprogress.css @@ -0,0 +1,62 @@ +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} +#nprogress .bar { + background: #fff; + position: fixed; + z-index: 1031; + top: 0; + left: 0; + width: 100%; + height: 3px; +} +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #29d, 0 0 5px #29d; + opacity: 1.0; + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 55px; +} +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + border: solid 2px transparent; + border-top-color: #fff; + border-left-color: #fff; + border-radius: 50%; + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} +.nprogress-custom-parent { + overflow: hidden; + position: relative; +} +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} +@-webkit-keyframes nprogress-spinner { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} +@keyframes nprogress-spinner { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + diff --git a/inc/nprogress.js b/inc/nprogress.js new file mode 100644 index 00000000..beb9d2cb --- /dev/null +++ b/inc/nprogress.js @@ -0,0 +1,480 @@ +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +;(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.NProgress = factory(); + } + +})(this, function() { + var NProgress = {}; + + NProgress.version = '0.2.0'; + + var Settings = NProgress.settings = { + minimum: 0.08, + easing: 'linear', + positionUsing: '', + speed: 200, + trickle: true, + trickleSpeed: 200, + showSpinner: true, + barSelector: '[role="bar"]', + spinnerSelector: '[role="spinner"]', + parent: 'body', + template: '
' + }; + + /** + * Updates configuration. + * + * NProgress.configure({ + * minimum: 0.1 + * }); + */ + NProgress.configure = function(options) { + var key, value; + for (key in options) { + value = options[key]; + if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; + } + + return this; + }; + + /** + * Last number. + */ + + NProgress.status = null; + + /** + * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. + * + * NProgress.set(0.4); + * NProgress.set(1.0); + */ + + NProgress.set = function(n) { + var started = NProgress.isStarted(); + + n = clamp(n, Settings.minimum, 1); + NProgress.status = (n === 1 ? null : n); + + var progress = NProgress.render(!started), + bar = progress.querySelector(Settings.barSelector), + speed = Settings.speed, + ease = Settings.easing; + + progress.offsetWidth; /* Repaint */ + + queue(function(next) { + // Set positionUsing if it hasn't already been set + if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); + + // Add transition + css(bar, barPositionCSS(n, speed, ease)); + + if (n === 1) { + // Fade out + css(progress, { + transition: 'none', + opacity: 1 + }); + progress.offsetWidth; /* Repaint */ + + setTimeout(function() { + css(progress, { + transition: 'all ' + speed + 'ms linear', + opacity: 0 + }); + setTimeout(function() { + NProgress.remove(); + next(); + }, speed); + }, speed); + } else { + setTimeout(next, speed); + } + }); + + return this; + }; + + NProgress.isStarted = function() { + return typeof NProgress.status === 'number'; + }; + + /** + * Shows the progress bar. + * This is the same as setting the status to 0%, except that it doesn't go backwards. + * + * NProgress.start(); + * + */ + NProgress.start = function() { + if (!NProgress.status) NProgress.set(0); + + var work = function() { + setTimeout(function() { + if (!NProgress.status) return; + NProgress.trickle(); + work(); + }, Settings.trickleSpeed); + }; + + if (Settings.trickle) work(); + + return this; + }; + + /** + * Hides the progress bar. + * This is the *sort of* the same as setting the status to 100%, with the + * difference being `done()` makes some placebo effect of some realistic motion. + * + * NProgress.done(); + * + * If `true` is passed, it will show the progress bar even if its hidden. + * + * NProgress.done(true); + */ + + NProgress.done = function(force) { + if (!force && !NProgress.status) return this; + + return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); + }; + + /** + * Increments by a random amount. + */ + + NProgress.inc = function(amount) { + var n = NProgress.status; + + if (!n) { + return NProgress.start(); + } else if(n > 1) { + return; + } else { + if (typeof amount !== 'number') { + if (n >= 0 && n < 0.2) { amount = 0.1; } + else if (n >= 0.2 && n < 0.5) { amount = 0.04; } + else if (n >= 0.5 && n < 0.8) { amount = 0.02; } + else if (n >= 0.8 && n < 0.99) { amount = 0.005; } + else { amount = 0; } + } + + n = clamp(n + amount, 0, 0.994); + return NProgress.set(n); + } + }; + + NProgress.trickle = function() { + return NProgress.inc(); + }; + + /** + * Waits for all supplied jQuery promises and + * increases the progress as the promises resolve. + * + * @param $promise jQUery Promise + */ + (function() { + var initial = 0, current = 0; + + NProgress.promise = function($promise) { + if (!$promise || $promise.state() === "resolved") { + return this; + } + + if (current === 0) { + NProgress.start(); + } + + initial++; + current++; + + $promise.always(function() { + current--; + if (current === 0) { + initial = 0; + NProgress.done(); + } else { + NProgress.set((initial - current) / initial); + } + }); + + return this; + }; + + })(); + + /** + * (Internal) renders the progress bar markup based on the `template` + * setting. + */ + + NProgress.render = function(fromStart) { + if (NProgress.isRendered()) return document.getElementById('nprogress'); + + addClass(document.documentElement, 'nprogress-busy'); + + var progress = document.createElement('div'); + progress.id = 'nprogress'; + progress.innerHTML = Settings.template; + + var bar = progress.querySelector(Settings.barSelector), + perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), + parent = document.querySelector(Settings.parent), + spinner; + + css(bar, { + transition: 'all 0 linear', + transform: 'translate3d(' + perc + '%,0,0)' + }); + + if (!Settings.showSpinner) { + spinner = progress.querySelector(Settings.spinnerSelector); + spinner && removeElement(spinner); + } + + if (parent != document.body) { + addClass(parent, 'nprogress-custom-parent'); + } + + parent.appendChild(progress); + return progress; + }; + + /** + * Removes the element. Opposite of render(). + */ + + NProgress.remove = function() { + removeClass(document.documentElement, 'nprogress-busy'); + removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent'); + var progress = document.getElementById('nprogress'); + progress && removeElement(progress); + }; + + /** + * Checks if the progress bar is rendered. + */ + + NProgress.isRendered = function() { + return !!document.getElementById('nprogress'); + }; + + /** + * Determine which positioning CSS rule to use. + */ + + NProgress.getPositioningCSS = function() { + // Sniff on document.body.style + var bodyStyle = document.body.style; + + // Sniff prefixes + var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : + ('MozTransform' in bodyStyle) ? 'Moz' : + ('msTransform' in bodyStyle) ? 'ms' : + ('OTransform' in bodyStyle) ? 'O' : ''; + + if (vendorPrefix + 'Perspective' in bodyStyle) { + // Modern browsers with 3D support, e.g. Webkit, IE10 + return 'translate3d'; + } else if (vendorPrefix + 'Transform' in bodyStyle) { + // Browsers without 3D support, e.g. IE9 + return 'translate'; + } else { + // Browsers without translate() support, e.g. IE7-8 + return 'margin'; + } + }; + + /** + * Helpers + */ + + function clamp(n, min, max) { + if (n < min) return min; + if (n > max) return max; + return n; + } + + /** + * (Internal) converts a percentage (`0..1`) to a bar translateX + * percentage (`-100%..0%`). + */ + + function toBarPerc(n) { + return (-1 + n) * 100; + } + + + /** + * (Internal) returns the correct CSS for changing the bar's + * position given an n percentage, and speed and ease from Settings + */ + + function barPositionCSS(n, speed, ease) { + var barCSS; + + if (Settings.positionUsing === 'translate3d') { + barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; + } else if (Settings.positionUsing === 'translate') { + barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; + } else { + barCSS = { 'margin-left': toBarPerc(n)+'%' }; + } + + barCSS.transition = 'all '+speed+'ms '+ease; + + return barCSS; + } + + /** + * (Internal) Queues a function to be executed. + */ + + var queue = (function() { + var pending = []; + + function next() { + var fn = pending.shift(); + if (fn) { + fn(next); + } + } + + return function(fn) { + pending.push(fn); + if (pending.length == 1) next(); + }; + })(); + + /** + * (Internal) Applies css properties to an element, similar to the jQuery + * css method. + * + * While this helper does assist with vendor prefixed property names, it + * does not perform any manipulation of values prior to setting styles. + */ + + var css = (function() { + var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], + cssProps = {}; + + function camelCase(string) { + return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { + return letter.toUpperCase(); + }); + } + + function getVendorProp(name) { + var style = document.body.style; + if (name in style) return name; + + var i = cssPrefixes.length, + capName = name.charAt(0).toUpperCase() + name.slice(1), + vendorName; + while (i--) { + vendorName = cssPrefixes[i] + capName; + if (vendorName in style) return vendorName; + } + + return name; + } + + function getStyleProp(name) { + name = camelCase(name); + return cssProps[name] || (cssProps[name] = getVendorProp(name)); + } + + function applyCss(element, prop, value) { + prop = getStyleProp(prop); + element.style[prop] = value; + } + + return function(element, properties) { + var args = arguments, + prop, + value; + + if (args.length == 2) { + for (prop in properties) { + value = properties[prop]; + if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); + } + } else { + applyCss(element, args[1], args[2]); + } + } + })(); + + /** + * (Internal) Determines if an element or space separated list of class names contains a class name. + */ + + function hasClass(element, name) { + var list = typeof element == 'string' ? element : classList(element); + return list.indexOf(' ' + name + ' ') >= 0; + } + + /** + * (Internal) Adds a class to an element. + */ + + function addClass(element, name) { + var oldList = classList(element), + newList = oldList + name; + + if (hasClass(oldList, name)) return; + + // Trim the opening space. + element.className = newList.substring(1); + } + + /** + * (Internal) Removes a class from an element. + */ + + function removeClass(element, name) { + var oldList = classList(element), + newList; + + if (!hasClass(element, name)) return; + + // Replace the class name. + newList = oldList.replace(' ' + name + ' ', ' '); + + // Trim the opening and closing spaces. + element.className = newList.substring(1, newList.length - 1); + } + + /** + * (Internal) Gets a space separated list of the class names on the element. + * The list is wrapped with a single space on each end to facilitate finding + * matches within the list. + */ + + function classList(element) { + return (' ' + (element && element.className || '') + ' ').replace(/\s+/gi, ' '); + } + + /** + * (Internal) Removes an element from the DOM. + */ + + function removeElement(element) { + element && element.parentNode && element.parentNode.removeChild(element); + } + + return NProgress; +}); diff --git a/inc/script.js b/inc/script.js index 44522976..f4242f82 100644 --- a/inc/script.js +++ b/inc/script.js @@ -49,10 +49,13 @@ var intervalId; function startSetInterval(interval) { if (cur_url[0] == "logs.py") { intervalId = setInterval('showLog()', interval); + showLog(); } else if (cur_url[0] == "viewsttats.py") { intervalId = setInterval('showStats()', interval); + showStats() } else if (cur_url[0] == "overview.py") { intervalId = setInterval('showOverview()', interval); + showOverview(); } else { intervalId = setInterval('document.location.reload()', interval); } @@ -84,6 +87,12 @@ function showOverview() { act: "overview", }, type: "GET", + beforeSend: function () { + NProgress.start(); + }, + complete: function () { + NProgress.done(); + }, success: function( data ) { var form = $("#ajax").html(); $("#ajax").html(data); @@ -100,10 +109,10 @@ function showStats() { }, type: "GET", beforeSend: function () { - $('#loading').show(); + NProgress.start(); }, complete: function () { - $("#loading").hide(); + NProgress.done(); }, success: function( data ) { var form = $("#ajax").html(); @@ -121,10 +130,58 @@ function showLog() { }, type: "GET", beforeSend: function () { - $('#loading').show(); + NProgress.start(); }, complete: function () { - $("#loading").hide(); + NProgress.done(); + }, + success: function( data ) { + var form = $("#ajax").html(); + $("#ajax").html(data); + } + } ); +} +function showRuntime() { + if($('#save').prop('checked')) { + saveCheck = "on"; + } else { + saveCheck = ""; + } + $.ajax( { + url: "options.py", + data: { + servaction: $('#servaction').val(), + serv: $("#serv").val(), + servbackend: $("#servbackend").val(), + save: saveCheck + }, + type: "GET", + beforeSend: function () { + NProgress.start(); + }, + complete: function () { + NProgress.done(); + }, + success: function( data ) { + var form = $("#ajax").html(); + $("#ajax").html(data); + } + } ); +} +function showCompare() { + $.ajax( { + url: "options.py", + data: { + serv: $("#serv").val(), + left: $('#left').val(), + right: $("#right").val() + }, + type: "GET", + beforeSend: function () { + NProgress.start(); + }, + complete: function () { + NProgress.done(); }, success: function( data ) { var form = $("#ajax").html(); diff --git a/inc/style.css b/inc/style.css index cd678b23..acfc6beb 100644 --- a/inc/style.css +++ b/inc/style.css @@ -19,6 +19,9 @@ h2 { margin-top: 0px; margin-bottom: 0px; } +h2 span { + width: 300px; +} h3 { margin-top: 10px; margin-bottom: 0px; @@ -55,11 +58,14 @@ pre { } .logoText { color: #EBF1F1; - font-size: 30px; + font-size: 25px; font-style: italic; font-weight: bold; - height: 52px; + height: 37px; background-color: #f4ab76; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; } .top-menu img { max-width: 125px; @@ -302,6 +308,7 @@ pre { padding: 10px; padding-left: 15px; border: none; + width: 25%; } .ro { border: none;