Hello community, here is the log from the commit of package hawk2 for openSUSE:Factory checked in at 2015-10-25 19:13:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hawk2 (Old) and /work/SRC/openSUSE:Factory/.hawk2.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hawk2" Changes: -------- --- /work/SRC/openSUSE:Factory/hawk2/hawk2.changes 2015-10-20 00:09:12.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.hawk2.new/hawk2.changes 2015-10-25 19:13:20.000000000 +0100 @@ -1,0 +2,17 @@ +Thu Oct 22 21:51:52 UTC 2015 - [email protected] + +- Update to version 1.0.0~alpha1+git.1445537620.7637b7f: + + Dashboard: Blinkenlights display for dashboard (bsc#951584) + + Command Log: Tag simulated commands (bsc#950618) + +------------------------------------------------------------------- +Wed Oct 21 16:03:52 UTC 2015 - [email protected] + +- Update to version 1.0.0~alpha1+git.1445441661.907341b: + + View: Fix overlapping growl notifications (bsc#950626) + + Cib: Patch remote node state from resource (bsc#949240) + + Cib: Don't try to read CIB XML if cluster is not running + + Dashboard: Fix adding/removing clusters + + Status: Show unclean status as error + +------------------------------------------------------------------- Old: ---- hawk2-1.0.0~alpha1+git.1445271072.1114d0a.tar.bz2 New: ---- hawk2-1.0.0~alpha1+git.1445537620.7637b7f.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hawk2.spec ++++++ --- /var/tmp/diff_new_pack.TYSlBv/_old 2015-10-25 19:13:21.000000000 +0100 +++ /var/tmp/diff_new_pack.TYSlBv/_new 2015-10-25 19:13:21.000000000 +0100 @@ -39,7 +39,7 @@ Summary: HA Web Konsole License: GPL-2.0 Group: %{pkg_group} -Version: 1.0.0~alpha1+git.1445271072.1114d0a +Version: 1.0.0~alpha1+git.1445537620.7637b7f Release: 0 Url: http://www.clusterlabs.org/wiki/Hawk Source: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.TYSlBv/_old 2015-10-25 19:13:21.000000000 +0100 +++ /var/tmp/diff_new_pack.TYSlBv/_new 2015-10-25 19:13:21.000000000 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/hawk.git</param> - <param name="changesrevision">1114d0a7161ac85b17d1eca5ad73fda1ccf2cc58</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">7637b7ffbf6688f8778d574971bff88d96cb204b</param></service></servicedata> \ No newline at end of file ++++++ hawk2-1.0.0~alpha1+git.1445271072.1114d0a.tar.bz2 -> hawk2-1.0.0~alpha1+git.1445537620.7637b7f.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/application.js new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/application.js --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/application.js 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/application.js 2015-10-22 23:51:44.000000000 +0200 @@ -6,6 +6,7 @@ //= require module/basics //= require module/help //= require module/forms +//= require module/statusmatrix //= require module/oplist //= require module/attrlist //= require module/wizattrlist diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/dashboard.js new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/dashboard.js --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/dashboard.js 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/dashboard.js 2015-10-22 23:51:44.000000000 +0200 @@ -1,4 +1,5 @@ // Copyright (c) 2009-2015 Tim Serong <[email protected]> +// Copyright (c) 2015 Kristoffer Gronlund <[email protected]> // See COPYING for license. // https://<host>:7630/cib/mini.json @@ -140,108 +141,46 @@ } text += '<div class="row">'; - text += '<div class="col-md-12">'; - text += '<div class="list-group">'; + text += '<div class="col-md-12 text-center">'; - var makePopoverButton = function(id, content, cls, title) { - var body = ""; - body += '<a tabindex="0" id="' + id + '" type="button" style="width: 100%;" class="btn list-group-item ' + cls + '" '; - body += 'data-trigger="focus" data-toggle="popover" title="' + title + '" '; - body += 'data-content="" '; - body += '>'; - body += content; - body += '</a>'; - return body; + var status_summary = { + nodes: [], + resources: [], + tickets: [] }; - var dlBegin = function() { - return '<dl class="dl-horizontal">'; - }; - - var dlEnd = function() { - return '</dl>'; - }; - - var dlAdd = function(title, text) { - return '<dt>' + title + '</dt><dd>' + text + '</dd>'; - } - - var descCache = {}; - - $.each(cib.node_states, function(state, count) { - if (count > 0) { - var details = dlBegin(); - $.each(cib.nodes, function(n, v) { - if (state == v) { - details += dlAdd(n, v); - } - }); - details += dlEnd(); - descCache['node_btn_' + state] = details; - - text += makePopoverButton('node_btn_' + state, count + ' ' + state + ' ' + plural('node', count), - listGroupClassForState(state), __("Details")); - } + $.each(cib.nodes, function(n, v) { + status_summary.nodes.push({name: n, state: v}); }); - $.each(cib.resource_states, function(state, count) { - if (count > 0) { - var details = dlBegin(); - $.each(cib.resources, function(rsc, locs) { - if (state == "stopped" && $.isEmptyObject(locs)) { - details += dlAdd(rsc, "<em>[stopped]</em>"); - } else { - var active = ""; - $.each(locs, function(node, st) { - if (st == state) { - active += node + " "; - } - }); - if (active != "") - details += dlAdd(rsc, active); - } - }); - details += dlEnd(); - descCache['rsc_btn_' + state] = details; + $.each(cib.resources, function(n, v) { + var rsc = {name: n, instances: []}; + $.each(v, function(nn, vv) { + rsc.instances.push({node: nn, state: vv}); + }); + status_summary.resources.push(rsc); + }); - text += makePopoverButton('rsc_btn_' + state, count + ' ' + state + ' ' + plural('resource', count), - listGroupClassForState(state), __("Details")); - } + $.each(cib.tickets, function(n, v) { + status_summary.tickets.push({name: n, state: v}); }); - $.each(cib.ticket_states, function(state, count) { - if (count > 0) { - var details = dlBegin(); - $.each(cib.tickets, function(i, e) { - $.each(e, function(name, tstate) { - if (state == tstate) { - details += dlAdd(name, state); - } - }); - }); - details += dlEnd(); - descCache['ticket1_btn_' + state] = details; + var cwidth = Math.min(status_summary.nodes.length * 36 + 36, 360); + var cheight = Math.min(status_summary.resources.length * 24 + status_summary.tickets.length * 24, 550); - text += makePopoverButton('ticket1_btn_' + state, count + ' ' + state + ' ' + plural('ticket', count), - listGroupClassForState(state), __("Details")); - } - }); + text += '<canvas width="' + cwidth + '" height="' + cheight + '"></canvas>'; text += '</div>'; text += '</div>'; - text += '</div>'; - var cs = checksum(text); + var cs = checksum(text + JSON.stringify(status_summary)); if (tag.data('hash') != cs) { tag.html(text); tag.data('hash', cs); - $.each(descCache, function(id, desc) { - var btn = $('#' + clusterId + ' #' + id); - btn.data("content", desc); - btn.popover({animation: true, html: true}); - }); + tag.find('canvas').cibStatusMatrix(status_summary); + } } @@ -459,20 +398,39 @@ return content; } + var updateLayout = function() { + var clusters = $("#clusters").children(); + var nclusters = clusters.length; + if (nclusters == 1) { + clusters.removeClass().addClass("col-md-6 col-md-offset-3"); + } else if (nclusters == 2) { + clusters.removeClass().addClass("col-md-6"); + } else if (nclusters == 3) { + clusters.removeClass().addClass("col-md-6 col-lg-4"); + } else if (nclusters == 4) { + clusters.removeClass().addClass("col-md-6"); + } else { + clusters.removeClass().addClass("col-md-4"); + } + }; + return function(data) { var clusterId = newClusterId(); var title = data.name || __("Local Status"); var content = basicCreateBody(clusterId, data); - var text = '<div class="col-lg-4 col-sm-6 col-xs-12">' + - '<div id="' + - clusterId + - '" class="panel panel-default" data-epoch="">' + - '<div class="panel-heading">' + - '<h3 class="panel-title">' + - '<span id="refresh"></span> ' + - '<a href="' + baseUrl(data) + '/">' + title + '</a>'; + var text = [ + '<div id="outer-', + clusterId, + '" class="col-lg-4 col-sm-6 col-xs-12">', + '<div id="', clusterId, '" class="panel panel-default" data-epoch="">', + '<div class="panel-heading">', + '<h3 class="panel-title">', + '<span id="refresh"></span> ', + '<a href="', baseUrl(data), '/">', title, '</a>' + ].join(''); + if (data.host != null) { var s_remove = __('Remove cluster _NAME_ from dashboard?').replace('_NAME_', data.name); text = text + @@ -493,16 +451,20 @@ '</div>'; $("#clusters").append(text); + updateLayout(); + if (data.host == null) { clusterRefresh(clusterId, data); } else { var close = $("#" + clusterId).find(".panel-title form"); close.on("ajax:success", function(e, data) { - $("#" + clusterId).remove(); + $("#" + clusterId).parent().remove(); + updateLayout(); $.growl({ message: __('Cluster removed successfully.')}, {type: 'success'}); }); close.on("ajax:error", function(e, xhr, status, error) { - $.growl({ message: __('Failed to remove cluster.')}, {type: 'danger'}); + $("#" + clusterId).parent().remove(); + $.growl({ message: __('Error removing cluster.')}, {type: 'danger'}); }); var body = $("#" + clusterId).find(".panel-body"); body.find("button.btn").click(function() { @@ -513,8 +475,18 @@ })(); var dashboardSetupAddClusterForm = function() { - $('form').toggleify(); - $('form').on("ajax:success", function(e, data, status, xhr) { + $('#new_cluster').toggleify(); + $('#new_cluster').on("submit", function() { + $('.modal-content .form-errors').append([ + '<div class="alert alert-info">', + '<i class="fa fa-refresh fa-2x fa-spin"></i> ', + __("Please wait..."), + '</div>' + ].join('')); + $(this).find('.submit').prop('disabled', true); + return true; // ensure submit actually happens + }); + $('#new_cluster').on("ajax:success", function(e, data, status, xhr) { $('#modal').modal('hide'); $('.modal-content').html(''); dashboardAddCluster(data); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/basics.js new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/basics.js --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/basics.js 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/basics.js 2015-10-22 23:51:44.000000000 +0200 @@ -20,7 +20,7 @@ $.growl( false, { - element: '#middle .container-fluid', + element: '#middle #flashes', mouse_over: 'pause', allow_dismiss: true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/nodes.js new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/nodes.js --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/nodes.js 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/nodes.js 2015-10-22 23:51:44.000000000 +0200 @@ -30,39 +30,32 @@ clickToSelect: true, class: 'col-sm-1', formatter: function(value, row, index) { + var icon = ['fa', 'fa-lg']; + var title = row.state; switch(row.state) { case 'online': - return [ - '<i class="fa fa-play fa-lg text-success" title="', - row.state, - '"></i>' - ].join(''); + icon.push('fa-play', 'text-success'); break; - case 'offline': - return [ - '<i class="fa fa-stop fa-lg text-info" title="', - row.state, - '"></i>' - ].join(''); + icon.push('fa-stop', 'text-info'); break; - case 'fence': - return [ - '<i class="fa fa-exclamation-triangle fa-lg text-danger" title="', - row.state, - '"></i>' - ].join(''); + icon.push('fa-exclamation-triangle', 'text-danger'); + break; + case 'unclean': + icon.push('fa-exclamation-triangle', 'text-danger'); break; - default: - return [ - '<i class="fa fa-question-circle fa-lg text-warning" title="', - row.state, - '"></i>' - ].join(''); + icon.push('fa-question-circle', 'text-warning'); break; } + var ret = ['<i class="', icon.join(' '), '" title="', title, '"></i>']; + + if (row.remote) { + ret.push(' <i class="fa fa-cloud text-info" title="', __("Remote"), '"></i>'); + } + + return ret.join(''); } }, { field: 'name', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/statusmatrix.js new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/statusmatrix.js --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/javascripts/module/statusmatrix.js 1970-01-01 01:00:00.000000000 +0100 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/javascripts/module/statusmatrix.js 2015-10-22 23:51:44.000000000 +0200 @@ -0,0 +1,201 @@ +// Copyright (c) 2015 Kristoffer Gronlund <[email protected]> +// See COPYING for license. + +// render canvas-based visualizations for cluster status. + + +$(function() { + $.fn.cibStatusMatrix = function(status, options) { + var canvas = this.get(0); + + var ctx = canvas.getContext("2d"); + + var defaults = { + colors: { + master: "#00aeef", + started: "#7ac143", + slave: "#f8981d", + stopped: "#d9534f", + pending: "#ffd457", + failed: "#ed1c24", + online: "#d0e4a6", + standby: "#747678", + offline: "#e4e5e6", + unclean: "#ec008c", + granted: "#c1d82f", + revoked: "#b5bbd4", + }, + icons: { + master: "fa-circle text-info", + started: "fa-circle text-success", + slave: "fa-circle text-warning", + stopped: "fa-minus-circle text-danger", + pending: "fa-question-circle text-warning", + failed: "fa-times-circle text-danger", + online: "fa-circle-thin text-success", + standby: "fa-dot-circle-o text-warning", + offline: "fa-minus-circle text-muted", + unclean: "fa-circle text-danger", + granted: "fa-check-circle text-success", + revoked: "fa-times-circle-o text-muted", + }, + title: __("Details"), + info_selector: "#cib-status-matrix-details", + info_template: [ + '<ul class="list-unstyled">', + '{{if item}}', + '<li><h3><i class="fa fa-lg {{>item_icon}}"></i> {{:item.name}} <small>{{:item.state}}</small></h3></li>', + '{{/if}}', + '{{if node}}', + '<li><h3><i class="fa fa-lg {{>node_icon}}"></i> {{:node.name}} <small>{{:node.state}}</small></h3></li>', + '{{/if}}', + '</ul>' + ].join('') + }; + if (options === undefined) { + options = defaults; + } else { + $.extend(defaults, options); + options = defaults; + } + + var colorByState = options.colors; + + var render = function(x, y, w, h, node, item) { + var inset = 3; + ctx.lineWidth = 3; + var hasStroke = false; + var hasFill = false; + + if (item != null) { + if (item.state in colorByState) { + hasFill = true; + ctx.fillStyle = colorByState[item.state]; + } + } + + if (node != null && node.state in colorByState) { + hasStroke = true; + ctx.strokeStyle = colorByState[node.state]; + } else { + ctx.strokeStyle = null; + } + + if (hasFill && !hasStroke) { + ctx.strokeStyle = ctx.fillStyle; + ctx.strokeRect(x + inset, y + inset, w - inset*2, h - inset*2); + } + if (hasFill) { + ctx.fillRect(x + inset, y + inset, w - inset*2, h - inset*2); + } + + if (hasStroke && !hasFill) { + ctx.fillStyle = ctx.strokeStyle; + ctx.fillRect(x + inset, y + inset, w - inset*2, h - inset*2); + } + if (hasStroke) { + ctx.strokeRect(x + inset, y + inset, w - inset*2, h - inset*2); + } + + if (!hasStroke && !hasFill) { + ctx.strokeStyle = options.colors.offline; + ctx.strokeRect(x + inset, y + inset, w - inset*2, h - inset*2); + } + }; + + + var width = $(this).attr("width") || 320; + var height = $(this).attr("height") || 240; + var ncols = status.nodes.length + 1; + var nrows = Math.max(status.resources.length + status.tickets.length, 1); + var cellw = width / ncols; + var cellh = height / nrows; + + var columns = []; + for (var i = 0; i < status.nodes.length; ++i) { + columns.push({name: status.nodes[i].name, state: status.nodes[i].state, row: []}); + columns[columns.length-1].row.length = nrows; + } + var stopped = {name: __("Stopped Resources"), state: null, row: []} + columns.push(stopped); + + $.each(columns, function(col, node) { + $.each(status.resources, function(row, rsc) { + var hasInstance = false; + if ("instances" in rsc) { + for (var i = 0; i < rsc.instances.length; i++) { + if (!hasInstance && rsc.instances[i].node == node.name) { + hasInstance = true; + var inst = {name: rsc.name, state: rsc.instances[i].state}; + node.row[row] = inst; + render(col*cellw, row*cellh, cellw, cellh, node, inst); + } + } + + if (rsc.instances.length == 0 && !("_stopped" in rsc)) { + rsc._stopped = true; + var srsc = {name: rsc.name, state: "stopped"}; + stopped.row[row] = srsc; + render((ncols-1)*cellw, row*cellh, cellw, cellh, stopped, srsc); + } + } + if (!hasInstance) { + render(col*cellw, row*cellh, cellw, cellh, node, null); + } + }); + }); + + var toffset = status.resources.length; + $.each(status.tickets, function(trow, ticket) { + var row = trow + toffset; + columns[0].row[row] = ticket; + render(0*cellw, row*cellh, width, cellh, null, ticket); + }); + + var lasthitx = null; + var lasthity = null; + + var infoTmpl = $.templates(options.info_template); + + this.on("mousemove", function(event) { + var rx = event.pageX - $(this).offset().left; + var ry = event.pageY - $(this).offset().top; + var hitx = Math.floor(rx / cellw); + var hity = Math.floor(ry / cellh); + var hitc = columns[hitx]; + if (hitc) { + var hitr = hitc.row[hity]; + if (lasthitx != hitx || lasthity != hity) { + var data = { title: options.title, node: null, item: null }; + if (hity >= status.resources.length) { + hitr = columns[0].row[hity]; + } else { + data.node = hitc; + data.node_icon = options.icons[hitc.state || "offline"]; + } + data.item = hitr; + if (hitr) { + data.item_icon = options.icons[hitr.state || "stopped"]; + } else { + data.item_icon = options.icons["stopped"]; + } + var abshitx = $(this).offset().left + hitx*cellw; + var abshity = $(this).offset().top + hity*cellh; + var target = $(options.info_selector); + target.html(infoTmpl.render(data)).width("auto"); + if (abshitx + (cellw / 2) > $(window).width() / 2) { + target.addClass("right").removeClass("left").offset({left: abshitx - 16 - target.outerWidth(), top: abshity - 16}); + } else { + target.removeClass("right").addClass("left").offset({left: abshitx + cellw + 16, top: abshity - 16}); + } + } + } + lasthitx = hitx; + lasthity = hity; + }).on("mouseleave", function(event) { + $(options.info_selector).fadeOut(200); + }).on("mouseenter", function(event) { + $(options.info_selector).fadeIn(200); + }); + }; +}); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/stylesheets/application.scss new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/stylesheets/application.scss --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/stylesheets/application.scss 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/stylesheets/application.scss 2015-10-22 23:51:44.000000000 +0200 @@ -21,3 +21,5 @@ @import "application/head"; @import "application/content"; @import "application/media"; + +@import "dashboard"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/stylesheets/dashboard.scss new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/stylesheets/dashboard.scss --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/assets/stylesheets/dashboard.scss 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/assets/stylesheets/dashboard.scss 2015-10-22 23:51:44.000000000 +0200 @@ -1,35 +1,17 @@ // Copyright (c) 2009-2015 Tim Serong <[email protected]> // See COPYING for license. -.cluster { - border: 1px solid #000; - float: left; - margin: 0.5em; - padding: 1em; - width: 18em; - background-color: #fff; -} - -.geoset { - border: 1px solid #000; - float: left; - margin: 0.5em; - padding-left: 0.5em; - padding-right: 0.5em; - background-color: #ccc; -} - -.mon-warning { - text-align: left; - font-weight: normal; +#cib-status-matrix-details { + display: none; + position: fixed; + padding: 0.5em 2em 0.5em 2em; + z-index: 10000; width: auto !important; -} - -.cluster-error { - font-weight: normal; - padding: 0.5em; -} -.dashboard-login { - margin-bottom: 0.5em; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/controllers/cib_controller.rb new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/controllers/cib_controller.rb --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/controllers/cib_controller.rb 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/controllers/cib_controller.rb 2015-10-22 23:51:44.000000000 +0200 @@ -16,21 +16,21 @@ format.json do render json: { errors: [e.message] }, status: :not_found end - format.any { head :not_found } + format.any { head :not_found } end rescue SecurityError => e respond_to do |format| format.json do render json: { errors: [e.message] }, status: :forbidden end - format.any { head :forbidden } + format.any { head :forbidden } end rescue RuntimeError => e respond_to do |format| format.json do render json: { errors: [e.message] }, status: :internal_server_error end - format.any { head :internal_server_error } + format.any { head :internal_server_error } end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/cib.rb new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/cib.rb --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/cib.rb 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/cib.rb 2015-10-22 23:51:44.000000000 +0200 @@ -100,65 +100,43 @@ }.tap do |result| if minimal result[:resources] = {} - - result[:resource_states] = { - pending: 0, - started: 0, - failed: 0, - master: 0, - slave: 0, - stopped: 0 - } - result[:nodes] = {} + result[:tickets] = {} - result[:node_states] = { - pending: 0, - online: 0, - standby: 0, - offline: 0, - unclean: 0 - } - - result[:tickets] = [] - - result[:ticket_states] = { - granted: 0, - revoked: 0 - } - - current_resources.each do |key, values| + resources.each do |rsc| + key = rsc[:id] result[:resources][key] ||= {} - - values[:instances].each do |_, attrs| - found = false + rsc[:instances].each do |_, attrs| [:master, :slave, :started, :failed, :pending].each do |rstate| if attrs[rstate] attrs[rstate].each do |n| result[:resources][key][n[:node]] = rstate end - result[:resource_states][rstate] += 1 - found = true end end - result[:resource_states][:stopped] += 1 unless found - end + end if rsc.key? :instances + rsc[:children].each do |child| + child[:instances].each do |_, attrs| + [:master, :slave, :started, :failed, :pending].each do |rstate| + if attrs[rstate] + attrs[rstate].each do |n| + result[:resources][key][n[:node]] = rstate + end + end + end + end if child.key? :instances + end if rsc.key? :children end current_nodes.each do |node| result[:nodes][node[:uname]] = node[:state] - - result[:node_states][node[:state]] += 1 end current_tickets.each do |key, values| - case - when values[:granted] - result[:tickets].push(key => :granted) - result[:ticket_states][:granted] += 1 + if values[:granted] + result[:tickets][key] = :granted else - result[:tickets].push(key => :revoked) - result[:ticket_states][:revoked] += 1 + result[:tickets][key] = :revoked end end @@ -214,6 +192,8 @@ end def find_node(id) + fail(RecordNotFound, id) if @xml.nil? + state = @nodes.select { |n| n[:id] == id } can_fence = @crm_config[:stonith_enabled] @@ -231,8 +211,9 @@ end def nodes_ordered - can_fence = @crm_config[:stonith_enabled] ret = [] + return ret if @xml.nil? + can_fence = @crm_config[:stonith_enabled] @xml.elements.each('cib/configuration/nodes/node') do |xml| id = xml.attributes['id'] state = @nodes.select { |n| n[:id] == id } @@ -458,7 +439,7 @@ case status.exitstatus when 0 @xml = REXML::Document.new(out) - unless @xml.root + unless @xml && @xml.root error _('Error invoking %{cmd}') % {:cmd => '/usr/sbin/cibadmin -Ql' } init_offline_cluster id, user, use_file return @@ -515,6 +496,7 @@ state = :unclean standby = false maintenance = @crm_config[:"maintenance-mode"] ? true : false + remote = n.attributes['type'] == 'remote' ns = @xml.elements["cib/status/node_state[@uname='#{uname}']"] if ns state = CibTools.determine_online_status(ns, crm_config[:"stonith-enabled"]) @@ -536,17 +518,38 @@ state = :standby end @nodes << Hashie::Mash.new( - :uname => uname, - :state => state, - :id => id, - :standby => standby, - :maintenance => maintenance + uname: uname, + state: state, + id: id, + standby: standby, + maintenance: maintenance, + remote: remote ) if state == :unclean error _('Node "%{node}" is UNCLEAN and needs to be fenced.') % { node: uname } end end + # add remote nodes that may not exist in cib/configuration/nodes/node + @xml.elements.each("cib/status/node_state[remote_node='true']") do |n| + uname = n.attributes['uname'] + id = n.attributes['id'] + # To determine the state of remote nodes, we need to look at + # the resource by the same name + state = :unknown + standby = false + unless @nodes.any? { |nod| nod[:id] == id } + @nodes << Hashie::Mash.new( + uname: uname, + state: state, + id: id, + standby: standby, + maintenance: maintenance, + remote: true + ) + end + end + @resources = [] @resources_by_id = {} @resource_count = 0 @@ -814,6 +817,20 @@ end end + # Now we can patch up the state of remote nodes + @nodes.each do |n| + if n[:remote] && n[:state] != :unclean + rsc = @resources_by_id[n[:id]] + if rsc && [:master, :slave, :started].include?(rsc[:state]) + n[:state] = :online + elsif rsc && [:failed, :pending].include?(rsc[:state]) + n[:state] = :unclean + else + n[:state] = :offline + end + end + end + # Now we can sort the node array @nodes.sort!{|a,b| a[:uname].natcmp(b[:uname], true)} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/cluster.rb new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/cluster.rb --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/cluster.rb 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/cluster.rb 2015-10-22 23:51:44.000000000 +0200 @@ -54,7 +54,7 @@ Rails.logger.debug "chmod 0660 #{fname}..." File.chmod(0660, fname) Rails.logger.debug "Copy #{fname}..." - out, err, rc = Invoker.instance.crm("cluster", "copy", fname) + out, err, rc = Util.run_as("root", "crm", "cluster", "copy", fname) Rails.logger.debug "Copy returned #{out} #{err} #{rc}" rc == 0 ? true : err end @@ -87,13 +87,13 @@ def remove(name) Rails.logger.debug "remove: Removing #{name}..." fname = "#{Rails.root}/tmp/dashboard.js" - return true unless File.exists?(fname) + return true unless File.exist?(fname) clusters = JSON.parse(File.read(fname)) - clusters = clusters.delete_if {|key, value| key == name } + clusters = clusters.delete_if { |key, _| key == name } Rails.logger.debug "remove: Writing #{fname}..." File.open(fname, "w") { |f| f.write(JSON.pretty_generate(clusters)) } File.chmod(0660, fname) - out, err, rc = Invoker.instance.crm("cluster", "copy", fname) + out, err, rc = Util.run_as("root", "crm", "cluster", "copy", fname) Rails.logger.debug "remove: Copy returned #{out} #{err} #{rc}" [out, err, rc] end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/node.rb new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/node.rb --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/models/node.rb 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/models/node.rb 2015-10-22 23:51:44.000000000 +0200 @@ -14,6 +14,7 @@ attribute :online, Boolean attribute :standby, Boolean attribute :ready, Boolean + attribute :remote, Boolean attribute :maintenance, Boolean attribute :fence, Boolean @@ -78,14 +79,12 @@ record.state = state[:state] record.standby = state[:standby] record.maintenance = state[:maintenance] + record.remote = state[:remote] record.fence = can_fence record.attrs = if xml.elements['instance_attributes'] vals = xml.elements['instance_attributes'].elements.collect do |e| - [ - e.attributes['name'], - e.attributes['value'] - ] + [e.attributes['name'], e.attributes['value']] end Hash[vals.sort] @@ -107,7 +106,7 @@ if record.utilization.any? Util.safe_x('/usr/sbin/crm_simulate', '-LU').split("\n").each do |line| - m = line.match /^Remaining:\s+([^\s]+)\s+capacity:\s+(.*)$/ + m = line.match(/^Remaining:\s+([^\s]+)\s+capacity:\s+(.*)$/) next unless m && m[1] == record.name @@ -140,12 +139,10 @@ # Record#find will fail when looking for nodes by their human-readable # name, so have to override here def find(id) - begin - super(id) - rescue Cib::RecordNotFound - # Can't find by id attribute, try by name attribute - super(name, 'name') - end + super(id) + rescue Cib::RecordNotFound + # Can't find by id attribute, try by name attribute + super(name, 'name') end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/dashboards/show.html.haml new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/dashboards/show.html.haml --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/dashboards/show.html.haml 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/dashboards/show.html.haml 2015-10-22 23:51:44.000000000 +0200 @@ -1,5 +1,3 @@ -= content_for :stylesheets do - = stylesheet_link_tag "dashboard" = content_for :javascripts do = javascript_include_tag "dashboard" @@ -13,6 +11,11 @@ #clusters.row -# passing null as name and host means to fetch local cluster information + - unless current_cib.offline? + :javascript + dashboardAddCluster({"name":null, "host":null, "port":null, https:null, "interval":10}); + :javascript - dashboardAddCluster({"name":null, "host":null, "port":null, https:null, "interval":10}); #{javascript_for_clusters @clusters} + + #cib-status-matrix-details diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/nodes/show.html.haml new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/nodes/show.html.haml --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/nodes/show.html.haml 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/nodes/show.html.haml 2015-10-22 23:51:44.000000000 +0200 @@ -10,6 +10,9 @@ = icon_text "server", _("Node: %{name}" % { name: @node.name }), class: "page" .modal-body + - if @node.remote + .alert.alert-info{role: :alert} + = _("Remote node.") %h4 = _("Utilization") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/shared/_flash.html.haml new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/shared/_flash.html.haml --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/app/views/shared/_flash.html.haml 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/app/views/shared/_flash.html.haml 2015-10-22 23:51:44.000000000 +0200 @@ -1,9 +1,10 @@ -- flash.each do |key, message| - .alert.alert-dismissible{ class: flash_class_for(key), role: "alert" } - %button.close{ type: "button", data: { dismiss: "alert" } } - %span{ aria: { hidden: "true" } } - × - %span.sr-only - = _("Close") +.row#flashes + - flash.each do |key, message| + .alert.alert-dismissible{ class: flash_class_for(key), role: "alert" } + %button.close{ type: "button", data: { dismiss: "alert" } } + %span{ aria: { hidden: "true" } } + × + %span.sr-only + = _("Close") - = simple_format message + = simple_format message diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/lib/crm_events.rb new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/lib/crm_events.rb --- old/hawk2-1.0.0~alpha1+git.1445271072.1114d0a/hawk/lib/crm_events.rb 2015-10-19 18:15:06.000000000 +0200 +++ new/hawk2-1.0.0~alpha1+git.1445537620.7637b7f/hawk/lib/crm_events.rb 2015-10-22 23:51:44.000000000 +0200 @@ -10,19 +10,22 @@ class CrmEvents include Singleton - TRUNC_LOG_SIZE = 32*1024 - MAX_LOG_SIZE = 128*1024 + TRUNC_LOG_SIZE = 32 * 1024 + MAX_LOG_SIZE = 128 * 1024 def truncate?(f) (f.mtime < 1.day.ago && f.size > TRUNC_LOG_SIZE) || f.size > MAX_LOG_SIZE end def push(cmd) + shadow_id = ENV["CIB_shadow"] + cmd = cmd.join(" ") if cmd.is_a? Array begin File.open(path, 'a') do |f| f.flock(File::LOCK_EX) f.truncate(0) if truncate? f + f << "# Shadow CIB: #{shadow_id} (Simulated)\n" unless shadow_id.nil? f << cmd f << "@@COMMAND-END@@\n" end @@ -33,16 +36,14 @@ end def cmds - begin - File.open(path, "r") do |f| - f.flock(File::LOCK_SH) - f.read.split("@@COMMAND-END@@\n").map do |cmd| - cmd.strip - end + File.open(path, "r") do |f| + f.flock(File::LOCK_SH) + f.read.split("@@COMMAND-END@@\n").map do |cmd| + cmd.strip end - rescue - [] end + rescue + [] end private
