puppet-herald 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -7
- data/.rubocop.yml +31 -0
- data/.rubocop_todo.yml +6 -0
- data/.travis.yml +7 -7
- data/Gemfile +5 -9
- data/README.md +152 -16
- data/Rakefile +67 -6
- data/bin/puppet-herald +1 -1
- data/config.ru +2 -2
- data/db/migrate/20141211165540_create_nodes.rb +5 -3
- data/db/migrate/20141211171305_create_reports.rb +12 -10
- data/db/migrate/20141211171326_create_log_entries.rb +9 -7
- data/db/schema.rb +24 -26
- data/lib/puppet-herald.rb +59 -21
- data/lib/puppet-herald/app/api.rb +111 -0
- data/lib/puppet-herald/app/configuration.rb +70 -0
- data/lib/puppet-herald/app/frontend.rb +61 -0
- data/lib/puppet-herald/{views → app/views}/app.erb +5 -8
- data/lib/puppet-herald/{views → app/views}/err500.erb +1 -4
- data/lib/puppet-herald/application.rb +27 -0
- data/lib/puppet-herald/cli.rb +66 -45
- data/lib/puppet-herald/client.rb +33 -0
- data/lib/puppet-herald/database.rb +84 -40
- data/lib/puppet-herald/javascript.rb +23 -17
- data/lib/puppet-herald/models/log-entry.rb +10 -3
- data/lib/puppet-herald/models/node.rb +15 -5
- data/lib/puppet-herald/models/report.rb +70 -63
- data/lib/puppet-herald/public/app.js +9 -8
- data/lib/puppet-herald/public/components/directives/status-button.html +1 -1
- data/lib/puppet-herald/public/components/directives/status-button.js +5 -3
- data/lib/puppet-herald/public/components/filters/filters.js +9 -4
- data/lib/puppet-herald/public/components/page.js +34 -0
- data/lib/puppet-herald/public/node/node.html +3 -1
- data/lib/puppet-herald/public/node/node.js +7 -4
- data/lib/puppet-herald/public/nodes/nodes.js +3 -2
- data/lib/puppet-herald/public/report/report.html +4 -1
- data/lib/puppet-herald/public/report/report.js +5 -3
- data/lib/puppet-herald/stubs/puppet.rb +20 -9
- data/lib/puppet-herald/version.rb +17 -7
- data/package.json +8 -3
- data/puppet-herald.gemspec +3 -6
- data/spec/integration/application_spec.rb +175 -0
- data/spec/integration/models/node_spec.rb +4 -4
- data/spec/integration/models/report_spec.rb +7 -7
- data/spec/spec_helper.rb +12 -7
- data/spec/support/active_record.rb +6 -10
- data/spec/support/reconnectdb.rb +13 -0
- data/spec/unit/puppet-herald/cli_spec.rb +45 -13
- data/spec/unit/puppet-herald/client_spec.rb +23 -0
- data/spec/unit/puppet-herald/database_spec.rb +8 -9
- data/spec/unit/puppet-herald/javascript_spec.rb +8 -13
- data/spec/unit/puppet-herald_spec.rb +4 -4
- data/test/javascript/karma.conf.js +43 -5
- data/test/javascript/src/app_test.js +90 -0
- data/test/javascript/src/components/artifact/artifact-directive_test.js +36 -0
- data/test/javascript/src/components/artifact/artifact_test.js +64 -0
- data/test/javascript/src/components/directives/status-button_test.js +159 -0
- data/test/javascript/src/components/filters/filters_test.js +35 -0
- data/test/javascript/src/node/node_test.js +87 -0
- data/test/javascript/src/nodes/nodes_test.js +56 -0
- data/test/javascript/src/report/report_test.js +94 -0
- metadata +98 -68
- data/lib/puppet-herald/app.rb +0 -103
- data/lib/puppet-herald/public/components/artifact/artifact-directive_test.js +0 -17
- data/spec/integration/app_spec.rb +0 -21
@@ -2,77 +2,84 @@ require 'puppet-herald/models/log-entry'
|
|
2
2
|
require 'puppet-herald/models/node'
|
3
3
|
require 'puppet-herald/stubs/puppet'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# A module for Herald
|
6
|
+
module PuppetHerald
|
7
|
+
# module for models
|
8
|
+
module Models
|
9
|
+
# A model for Report
|
10
|
+
class Report < ActiveRecord::Base
|
11
|
+
belongs_to :node
|
12
|
+
has_many :log_entries, dependent: :delete_all
|
8
13
|
|
9
|
-
|
10
|
-
|
11
|
-
|
14
|
+
class << self
|
15
|
+
# Gets a report with prefetched log entries
|
16
|
+
# @param id [Integer] a in of report to get
|
17
|
+
# @return [Report, nil] fetched report or nil
|
18
|
+
def get_with_log_entries(id)
|
19
|
+
Report.joins(:log_entries).includes(:log_entries).find_by_id(id)
|
20
|
+
end
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
node = parse_node parsed, report
|
22
|
+
# Creates a report from given YAML report file
|
23
|
+
# @param yaml [String] a puppet report YAML as string
|
24
|
+
# @return [Report] created report
|
25
|
+
def create_from_yaml(yaml)
|
26
|
+
parsed = parse_yaml yaml
|
27
|
+
report = Report.new
|
20
28
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
29
|
+
parse_properties parsed, report
|
30
|
+
parse_logs parsed, report
|
31
|
+
node = parse_node parsed, report
|
25
32
|
|
26
|
-
|
33
|
+
report.save
|
34
|
+
node.save
|
35
|
+
report
|
36
|
+
end
|
27
37
|
|
28
|
-
|
29
|
-
node = Node.find_by_name(parsed.host)
|
30
|
-
if node.nil?
|
31
|
-
node = Node.new
|
32
|
-
node.name = parsed.host
|
33
|
-
node.no_of_reports = 0
|
34
|
-
end
|
35
|
-
report.node = node
|
36
|
-
node.reports << report
|
37
|
-
node.no_of_reports += 1
|
38
|
-
node.status = parsed.status
|
39
|
-
node.last_run = parsed.time
|
40
|
-
return node
|
41
|
-
end
|
38
|
+
private
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
def parse_node(parsed, report)
|
41
|
+
node = Node.find_by_name(parsed.host)
|
42
|
+
if node.nil?
|
43
|
+
node = Node.new
|
44
|
+
node.name = parsed.host
|
45
|
+
node.no_of_reports = 0
|
46
|
+
end
|
47
|
+
report.node = node
|
48
|
+
node.reports << report
|
49
|
+
node.no_of_reports += 1
|
50
|
+
node.status = parsed.status
|
51
|
+
node.last_run = parsed.time
|
52
|
+
node
|
53
|
+
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
'level', 'message',
|
58
|
-
'source', 'time'
|
59
|
-
]
|
60
|
-
copy_attrs in_log, log, attr_to_copy
|
61
|
-
log.report = report
|
62
|
-
report.log_entries << log
|
63
|
-
end
|
64
|
-
end
|
55
|
+
def parse_properties(parsed, report)
|
56
|
+
attr_to_copy = %w(status environment transaction_uuid time puppet_version kind host configuration_version)
|
57
|
+
copy_attrs parsed, report, attr_to_copy
|
58
|
+
end
|
65
59
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
def parse_logs(parsed, report)
|
61
|
+
parsed.logs.each do |in_log|
|
62
|
+
log = LogEntry.new
|
63
|
+
attr_to_copy = %w(level message source time)
|
64
|
+
copy_attrs in_log, log, attr_to_copy
|
65
|
+
log.report = report
|
66
|
+
report.log_entries << log
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_yaml(yaml)
|
71
|
+
require 'yaml'
|
72
|
+
raw = YAML.parse yaml
|
73
|
+
raw.to_ruby
|
74
|
+
end
|
71
75
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
def copy_attrs(from, to, attrs)
|
77
|
+
attrs.each do |at|
|
78
|
+
value = from.send at
|
79
|
+
to.send "#{at}=", value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
76
83
|
end
|
77
84
|
end
|
78
|
-
end
|
85
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
var app = angular.module('herald' , [
|
5
5
|
'ngRoute',
|
6
|
+
'herald.page',
|
6
7
|
'herald.nodes',
|
7
8
|
'herald.node',
|
8
9
|
'herald.report',
|
@@ -14,14 +15,14 @@
|
|
14
15
|
$routeProvider.otherwise({redirectTo: '/nodes'});
|
15
16
|
}]);
|
16
17
|
|
17
|
-
app.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
app.controller('AppController', ['Page', '$rootScope', function(Page, $rootScope) {
|
19
|
+
var ctrl = this;
|
20
|
+
this.page = null;
|
21
|
+
this.target = null;
|
22
|
+
$rootScope.$on('Page::titleChanged', function(event, title, target) {
|
23
|
+
ctrl.page = title;
|
24
|
+
ctrl.target = target;
|
25
|
+
});
|
25
26
|
}]);
|
26
27
|
|
27
28
|
})();
|
@@ -10,8 +10,8 @@
|
|
10
10
|
|
11
11
|
$scope.$location = $location;
|
12
12
|
|
13
|
-
$scope.navigate = function() {
|
14
|
-
var target =
|
13
|
+
$scope.navigate = function(route, id) {
|
14
|
+
var target = route.replace(':id', id);
|
15
15
|
this.$location.path(target);
|
16
16
|
};
|
17
17
|
|
@@ -36,6 +36,7 @@
|
|
36
36
|
case 'unchanged': return 'success';
|
37
37
|
case 'changed': return 'info';
|
38
38
|
case 'failed': return 'danger';
|
39
|
+
case 'pending': return 'warning';
|
39
40
|
default: return 'default';
|
40
41
|
}
|
41
42
|
}
|
@@ -47,7 +48,8 @@
|
|
47
48
|
case 'unchanged': return 'ok';
|
48
49
|
case 'changed': return 'pencil';
|
49
50
|
case 'failed': return 'remove';
|
50
|
-
|
51
|
+
case 'pending': return 'asterisk';
|
52
|
+
default: return 'sign';
|
51
53
|
}
|
52
54
|
}
|
53
55
|
});
|
@@ -1,12 +1,17 @@
|
|
1
1
|
'use strict';
|
2
2
|
|
3
|
-
angular.module('herald.filters', [
|
4
|
-
])
|
3
|
+
angular.module('herald.filters', [])
|
5
4
|
|
6
5
|
.filter('capitalize', function() {
|
7
6
|
return function(input) {
|
8
|
-
var
|
9
|
-
|
7
|
+
var text;
|
8
|
+
if (input == null) {
|
9
|
+
text = '';
|
10
|
+
} else {
|
11
|
+
text = input.toString();
|
12
|
+
}
|
13
|
+
var first = text.substring(0, 1);
|
14
|
+
var rest = text.substring(1);
|
10
15
|
return first.toUpperCase() + rest;
|
11
16
|
};
|
12
17
|
});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
(function(angular){
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
var module = angular.module('herald.page' , []);
|
5
|
+
|
6
|
+
module.factory('Page', ['$document', '$rootScope', function($document, $rootScope) {
|
7
|
+
var root = $document;
|
8
|
+
var base = root[0].title
|
9
|
+
var title = null;
|
10
|
+
var target = null;
|
11
|
+
var service = {
|
12
|
+
title: function(newTitle, newTarget, joiner) {
|
13
|
+
var merged = newTitle + '';
|
14
|
+
if(typeof(joiner) === 'undefined') joiner = ': ';
|
15
|
+
if (typeof(newTarget) !== 'undefined') {
|
16
|
+
merged = merged + joiner + newTarget;
|
17
|
+
}
|
18
|
+
var whole = merged + ' | ' + base;
|
19
|
+
root[0].title = whole;
|
20
|
+
title = newTitle;
|
21
|
+
target = newTarget;
|
22
|
+
$rootScope.$emit('Page::titleChanged', title, target, merged, whole);
|
23
|
+
},
|
24
|
+
actualTitle: function() {
|
25
|
+
return title;
|
26
|
+
},
|
27
|
+
actualTarget: function() {
|
28
|
+
return target;
|
29
|
+
}
|
30
|
+
};
|
31
|
+
return service;
|
32
|
+
}]);
|
33
|
+
|
34
|
+
})(angular);
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<div class="panel panel-primary" ng-controller="NodeController as ctrl">
|
2
2
|
<!-- Default panel contents -->
|
3
|
-
<div class="panel-heading">Reports for
|
3
|
+
<div class="panel-heading">Reports for
|
4
|
+
<samp>{{ ctrl.node.name }}</samp> <span class="badge">{{ ctrl.node.reports.length }}</span>
|
5
|
+
</div>
|
4
6
|
|
5
7
|
<!-- Table -->
|
6
8
|
<table class="table table-striped table-hover">
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
angular.module('herald.node', [
|
4
4
|
'ngRoute',
|
5
|
-
'herald.
|
5
|
+
'herald.page',
|
6
|
+
'herald.directives',
|
7
|
+
'angularMoment'
|
6
8
|
])
|
7
9
|
|
8
10
|
.config(['$routeProvider', function($routeProvider) {
|
@@ -12,13 +14,14 @@ angular.module('herald.node', [
|
|
12
14
|
});
|
13
15
|
}])
|
14
16
|
|
15
|
-
.controller('NodeController', ['$http', '$routeParams', function($http, $routeParams) {
|
17
|
+
.controller('NodeController', ['$http', '$routeParams', 'Page', function($http, $routeParams, Page) {
|
16
18
|
var ctrl = this;
|
17
19
|
ctrl.node = null;
|
18
|
-
|
20
|
+
Page.title('Node');
|
19
21
|
this.nodeId = $routeParams.nodeId;
|
20
22
|
|
21
|
-
$http.get('/api/v1/
|
23
|
+
$http.get('/api/v1/nodes/' + this.nodeId).success(function(data) {
|
22
24
|
ctrl.node = data;
|
25
|
+
Page.title('Node', data.name);
|
23
26
|
});
|
24
27
|
}]);
|
@@ -3,6 +3,7 @@
|
|
3
3
|
angular.module('herald.nodes', [
|
4
4
|
'ngRoute',
|
5
5
|
'herald.directives',
|
6
|
+
'herald.page',
|
6
7
|
'angularMoment'
|
7
8
|
])
|
8
9
|
|
@@ -13,8 +14,8 @@ angular.module('herald.nodes', [
|
|
13
14
|
});
|
14
15
|
}])
|
15
16
|
|
16
|
-
.controller('NodesController', ['$http', '
|
17
|
-
|
17
|
+
.controller('NodesController', ['$http', 'Page', function($http, Page) {
|
18
|
+
Page.title('All nodes');
|
18
19
|
var ctrl = this;
|
19
20
|
ctrl.all = [];
|
20
21
|
|
@@ -1,6 +1,9 @@
|
|
1
1
|
<div class="panel panel-primary" ng-controller="ReportController as ctrl">
|
2
2
|
<!-- Default panel contents -->
|
3
|
-
<div class="panel-heading">Report
|
3
|
+
<div class="panel-heading">Report:
|
4
|
+
<samp>{{ ctrl.report.configuration_version }}</samp>
|
5
|
+
<span class="badge">{{ ctrl.report.log_entries.length }}</span>
|
6
|
+
</div>
|
4
7
|
|
5
8
|
<!-- Table -->
|
6
9
|
<table class="table table-condensed table-hover herald-table-report">
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
angular.module('herald.report', [
|
4
4
|
'ngRoute',
|
5
|
+
'herald.page',
|
5
6
|
'herald.directives'
|
6
7
|
])
|
7
8
|
|
@@ -12,13 +13,14 @@ angular.module('herald.report', [
|
|
12
13
|
});
|
13
14
|
}])
|
14
15
|
|
15
|
-
.controller('ReportController', ['$http', '$routeParams', function($http, $routeParams) {
|
16
|
+
.controller('ReportController', ['$http', '$routeParams', 'Page', function($http, $routeParams, Page) {
|
17
|
+
Page.title('Report');
|
16
18
|
var ctrl = this;
|
17
19
|
ctrl.report = null;
|
18
|
-
|
19
20
|
this.reportId = $routeParams.reportId;
|
20
21
|
|
21
|
-
$http.get('/api/v1/
|
22
|
+
$http.get('/api/v1/reports/' + this.reportId).success(function(data) {
|
22
23
|
ctrl.report = data;
|
24
|
+
Page.title('Report', data.configuration_version);
|
23
25
|
});
|
24
26
|
}]);
|
@@ -1,29 +1,40 @@
|
|
1
|
+
# A stub Puppet module
|
1
2
|
module Puppet
|
3
|
+
# A stub Puppet module
|
2
4
|
module Transaction
|
3
|
-
|
5
|
+
# A stub Puppet class
|
4
6
|
class Report
|
5
|
-
|
7
|
+
# A puppet variable from report
|
8
|
+
# @return [String] a puppet set variable
|
9
|
+
attr_accessor :host, :time, :kind, :puppet_version, :configuration_version
|
10
|
+
|
11
|
+
# A puppet variable from report
|
12
|
+
# @return [String] a puppet set variable
|
13
|
+
attr_accessor :transaction_uuid, :environment, :status, :logs
|
6
14
|
end
|
7
15
|
|
16
|
+
# A stub Puppet class
|
8
17
|
class Event
|
9
|
-
|
10
18
|
end
|
11
|
-
|
12
19
|
end
|
20
|
+
|
21
|
+
# A stub Puppet class
|
13
22
|
class Resource
|
23
|
+
# A stub Puppet class
|
14
24
|
class Status
|
15
|
-
|
16
25
|
end
|
17
26
|
end
|
27
|
+
# A stub Puppet module
|
18
28
|
module Util
|
19
|
-
|
29
|
+
# A stub Puppet class
|
20
30
|
class Log
|
31
|
+
# A puppet variable from report
|
32
|
+
# @return [String] a puppet set variable
|
21
33
|
attr_accessor :level, :message, :source, :time, :line, :tags
|
22
34
|
end
|
23
35
|
|
36
|
+
# A stub Puppet class
|
24
37
|
class Metric
|
25
|
-
|
26
38
|
end
|
27
|
-
|
28
39
|
end
|
29
|
-
end
|
40
|
+
end
|
@@ -1,20 +1,30 @@
|
|
1
|
+
# A module for Herald
|
1
2
|
module PuppetHerald
|
2
|
-
|
3
|
-
|
3
|
+
# Prepare version
|
4
|
+
#
|
5
|
+
# @param desired [String] a desired version
|
6
|
+
# @return [String] a prepared version
|
7
|
+
def self.version_prep(desired)
|
4
8
|
version = desired
|
5
9
|
if desired.match(/[^0-9\.]+/)
|
6
10
|
git = `git describe --tags --dirty --always`
|
7
|
-
version +=
|
11
|
+
version += '.' + git.gsub('-', '.')
|
8
12
|
end
|
9
|
-
|
13
|
+
version.strip
|
10
14
|
end
|
11
15
|
|
12
|
-
|
16
|
+
# Version for Herald
|
17
|
+
VERSION = version_prep '0.2.0'
|
18
|
+
# Lincense for Herald
|
13
19
|
LICENSE = 'Apache 2.0'
|
20
|
+
# Project name
|
14
21
|
NAME = 'Puppet Herald'
|
22
|
+
# Package (gem) for Herald
|
15
23
|
PACKAGE = 'puppet-herald'
|
24
|
+
# A summary info
|
16
25
|
SUMMARY = 'a Puppet report processor'
|
17
|
-
|
26
|
+
# A description info
|
27
|
+
DESCRIPTION = 'Provides a gateway for consuming puppet reports, a REST API and a simple Web app to display reports.'
|
28
|
+
# A homepage for Herald
|
18
29
|
HOMEPAGE = 'https://github.com/wavesoftware/gem-puppet-herald'
|
19
|
-
|
20
30
|
end
|