puppet-herald 0.2.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.gitignore +3 -0
- data/.jshintrc +19 -0
- data/Gemfile +25 -12
- data/Gemfile.local.example +3 -0
- data/Guardfile +57 -0
- data/README.md +1 -1
- data/Rakefile +100 -20
- data/db/migrate/20141218200108_remove_no_of_reports_from_nodes.rb +7 -0
- data/lib/puppet-herald.rb +95 -65
- data/lib/puppet-herald/app/api.rb +79 -12
- data/lib/puppet-herald/app/configuration.rb +47 -15
- data/lib/puppet-herald/app/frontend.rb +6 -6
- data/lib/puppet-herald/app/views/app.erb +14 -20
- data/lib/puppet-herald/app/views/err500.erb +8 -5
- data/lib/puppet-herald/application.rb +9 -1
- data/lib/puppet-herald/cli.rb +5 -11
- data/lib/puppet-herald/database.rb +1 -7
- data/lib/puppet-herald/javascript.rb +16 -10
- data/lib/puppet-herald/models.rb +47 -0
- data/lib/puppet-herald/models/log-entry.rb +2 -0
- data/lib/puppet-herald/models/node.rb +49 -2
- data/lib/puppet-herald/models/report.rb +33 -9
- data/lib/puppet-herald/project.js +46 -0
- data/lib/puppet-herald/public/app.js +11 -9
- data/lib/puppet-herald/public/bower.json +10 -3
- data/lib/puppet-herald/public/components/artifact/artifact-directive.js +4 -0
- data/lib/puppet-herald/public/components/artifact/artifact.js +1 -3
- data/lib/puppet-herald/public/components/directives/directives.js +5 -1
- data/lib/puppet-herald/public/components/directives/status-button.html +1 -1
- data/lib/puppet-herald/public/components/directives/status-button.js +11 -11
- data/lib/puppet-herald/public/components/filters/filters.js +6 -2
- data/lib/puppet-herald/public/components/page.js +2 -2
- data/lib/puppet-herald/public/components/pagination.js +142 -0
- data/lib/puppet-herald/public/components/settings.js +25 -0
- data/lib/puppet-herald/public/css/herald.css +100 -3
- data/lib/puppet-herald/public/general/app.html +73 -0
- data/lib/puppet-herald/public/img/shield97-white.svg +53 -0
- data/lib/puppet-herald/public/img/shield97.png +0 -0
- data/lib/puppet-herald/public/node/node.html +27 -9
- data/lib/puppet-herald/public/node/node.js +43 -15
- data/lib/puppet-herald/public/nodes/nodes.html +25 -7
- data/lib/puppet-herald/public/nodes/nodes.js +29 -14
- data/lib/puppet-herald/public/report/report.html +60 -13
- data/lib/puppet-herald/public/report/report.js +21 -14
- data/lib/puppet-herald/public/router.js +55 -0
- data/lib/puppet-herald/purgecronjob.rb +35 -0
- data/lib/puppet-herald/version.rb +2 -2
- data/package.json +14 -16
- data/puppet-herald.gemspec +12 -7
- data/spec/integration/app/configuration_spec.rb +33 -0
- data/spec/integration/application_spec.rb +139 -20
- data/spec/integration/fixtures/nodes.yml +13 -0
- data/spec/integration/fixtures/pending-notify.yaml +346 -0
- data/spec/integration/fixtures/reports.yml +61 -0
- data/spec/integration/models/node_spec.rb +12 -3
- data/spec/integration/models/report_spec.rb +60 -4
- data/spec/spec_helper.rb +6 -10
- data/spec/support/active_record.rb +1 -0
- data/spec/support/fixtures.rb +16 -0
- data/spec/unit/puppet-herald/cli_spec.rb +4 -4
- data/spec/unit/puppet-herald/database_spec.rb +5 -3
- data/spec/unit/puppet-herald/purgecronjob_spec.rb +37 -0
- data/test/javascript/.bowerrc +3 -0
- data/test/javascript/bower.json +21 -0
- data/test/javascript/karma.conf.js +17 -22
- data/test/javascript/src/app_test.js +10 -61
- data/test/javascript/src/components/directives/status-button_test.js +10 -10
- data/test/javascript/src/components/paginate_test.js +183 -0
- data/test/javascript/src/node/node_test.js +16 -6
- data/test/javascript/src/nodes/nodes_test.js +14 -2
- data/test/javascript/src/report/report_test.js +6 -6
- data/test/javascript/src/router_test.js +79 -0
- metadata +642 -23
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'puppet-herald'
|
2
|
-
require 'uglifier'
|
3
|
-
|
4
1
|
# A module for Herald
|
5
2
|
module PuppetHerald
|
6
3
|
# A javascript processing class
|
@@ -14,11 +11,13 @@ module PuppetHerald
|
|
14
11
|
# Returns a list of JS files to be inserted into main HTML
|
15
12
|
# @return [Array] list of JS's
|
16
13
|
def files
|
14
|
+
require 'puppet-herald'
|
17
15
|
@files = nil if PuppetHerald.in_dev?
|
18
16
|
if @files.nil?
|
19
17
|
public_dir = PuppetHerald.relative_dir(@base)
|
20
18
|
all = Dir.chdir(public_dir) { Dir.glob('**/*.js') }
|
21
|
-
|
19
|
+
all = all.reverse.reject { |file| file.match(/_test\.js$/) }
|
20
|
+
@files = all.reject { |file| file.match(/bower_components/) }
|
22
21
|
end
|
23
22
|
@files
|
24
23
|
end
|
@@ -27,14 +26,21 @@ module PuppetHerald
|
|
27
26
|
# @param mapname [String] name of source map to be put into uglified JS
|
28
27
|
# @return [Hash] a hash with uglified JS and source map
|
29
28
|
def uglify(mapname)
|
30
|
-
|
29
|
+
require 'uglifier'
|
30
|
+
filenames = files
|
31
|
+
sources = filenames.collect { |file| File.read("#{@base}/#{file}") }
|
31
32
|
source = sources.join "\n"
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
options = {
|
34
|
+
source_map_url: mapname,
|
35
|
+
source_filename: filenames[0],
|
36
|
+
compress: {
|
37
|
+
angular: true,
|
38
|
+
hoist_vars: true
|
39
|
+
}
|
37
40
|
}
|
41
|
+
uglifier = Uglifier.new(options)
|
42
|
+
uglified, source_map = uglifier.compile_with_map(source)
|
43
|
+
{ 'js' => uglified, 'js.map' => source_map }
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# A module for Herald
|
2
|
+
module PuppetHerald
|
3
|
+
# module for models
|
4
|
+
module Models
|
5
|
+
# Pagianation object
|
6
|
+
class Pagination
|
7
|
+
# Pagination headers
|
8
|
+
KEYS = {
|
9
|
+
page: 'X-Paginate-Page',
|
10
|
+
limit: 'X-Paginate-Limit',
|
11
|
+
total: 'X-Paginate-Elements',
|
12
|
+
pages: 'X-Paginate-Pages'
|
13
|
+
}
|
14
|
+
# Pagination attribute limit
|
15
|
+
# @return [Integer] pagination
|
16
|
+
attr_reader :page, :limit, :pages, :total
|
17
|
+
# Pagination attribute offset
|
18
|
+
# @return [Integer] pagination
|
19
|
+
def offset
|
20
|
+
(page - 1) * limit
|
21
|
+
end
|
22
|
+
# Sets a total elements for pagination
|
23
|
+
# @param total [Integer] a total number of elements
|
24
|
+
# @return [nil]
|
25
|
+
def total=(total)
|
26
|
+
@total = total.to_i
|
27
|
+
@pages = (@total / @limit.to_f).ceil
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
# A constructor
|
31
|
+
#
|
32
|
+
# @param page [Integer] page to fetch
|
33
|
+
# @param limit [Integer] pagination limit
|
34
|
+
def initialize(page, limit)
|
35
|
+
msg = 'Invalid value for pagination'
|
36
|
+
fail ArgumentError, "#{msg} limit - #{limit.inspect}" unless limit.to_i >= 1
|
37
|
+
fail ArgumentError, "#{msg} page #{page.inspect}" if page.to_i < 1
|
38
|
+
@limit = limit.to_i
|
39
|
+
@page = page.to_i
|
40
|
+
@total = nil
|
41
|
+
@pages = nil
|
42
|
+
end
|
43
|
+
# A default pagination settings
|
44
|
+
DEFAULT = PuppetHerald::Models::Pagination.new(1, 20)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'puppet-herald/models'
|
2
|
+
require 'puppet-herald/models/report'
|
3
|
+
require 'sinatra/activerecord'
|
4
|
+
|
1
5
|
# A module for Herald
|
2
6
|
module PuppetHerald
|
3
7
|
# module for models
|
@@ -6,11 +10,54 @@ module PuppetHerald
|
|
6
10
|
class Node < ActiveRecord::Base
|
7
11
|
has_many :reports, dependent: :delete_all
|
8
12
|
|
13
|
+
# Paginete thru nodes reports
|
14
|
+
#
|
15
|
+
# @param pagination [PuppetHerald::Models::Pagination] a pagination
|
16
|
+
# @return [Node] fetched node
|
17
|
+
def paginate_reports(pagination)
|
18
|
+
pagination.total = no_of_reports
|
19
|
+
paginated = reports.order(time: :desc).limit(pagination.limit)
|
20
|
+
.offset(pagination.offset)
|
21
|
+
duplicate = dup
|
22
|
+
duplicate.reports = paginated
|
23
|
+
duplicate.id = id
|
24
|
+
duplicate.readonly!
|
25
|
+
duplicate
|
26
|
+
end
|
27
|
+
|
28
|
+
# Gets number of reports for node
|
29
|
+
#
|
30
|
+
# @return [Integer] number of node's reports
|
31
|
+
def no_of_reports
|
32
|
+
PuppetHerald::Models::Report.where(node_id: id).count
|
33
|
+
end
|
34
|
+
|
35
|
+
# Deletes nodes that doesn't have reports
|
36
|
+
#
|
37
|
+
# @return [Integer] number of empty node deleted
|
38
|
+
def self.delete_empty
|
39
|
+
joinsql = 'LEFT JOIN "reports" ON "reports"."node_id" = "nodes"."id"'
|
40
|
+
wheresql = '"reports"."node_id" IS NULL'
|
41
|
+
joins(joinsql).where(wheresql).delete_all if joins(joinsql).where(wheresql).count > 0
|
42
|
+
end
|
43
|
+
|
9
44
|
# Gets a node with prefetched reports
|
45
|
+
#
|
10
46
|
# @param id [Integer] a in of node to get
|
47
|
+
# @param pagination [PuppetHerald::Models::Pagination] a pagination
|
11
48
|
# @return [Node, nil] fetched node or nil
|
12
|
-
def self.
|
13
|
-
|
49
|
+
def self.with_reports(id, pagination = PuppetHerald::Models::Pagination::DEFAULT)
|
50
|
+
node = find_by_id(id)
|
51
|
+
node.paginate_reports pagination unless node.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Gets a paginated nodes
|
55
|
+
#
|
56
|
+
# @param pagination [PuppetHerald::Models::Pagination] a pagination
|
57
|
+
# @return [Node[]] nodes
|
58
|
+
def self.paginate(pagination)
|
59
|
+
pagination.total = count
|
60
|
+
order(last_run: :desc).limit(pagination.limit).offset(pagination.offset)
|
14
61
|
end
|
15
62
|
end
|
16
63
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'puppet-herald/models/log-entry'
|
2
2
|
require 'puppet-herald/models/node'
|
3
3
|
require 'puppet-herald/stubs/puppet'
|
4
|
+
require 'sinatra/activerecord'
|
4
5
|
|
5
6
|
# A module for Herald
|
6
7
|
module PuppetHerald
|
@@ -15,7 +16,7 @@ module PuppetHerald
|
|
15
16
|
# Gets a report with prefetched log entries
|
16
17
|
# @param id [Integer] a in of report to get
|
17
18
|
# @return [Report, nil] fetched report or nil
|
18
|
-
def
|
19
|
+
def with_log_entries(id)
|
19
20
|
Report.joins(:log_entries).includes(:log_entries).find_by_id(id)
|
20
21
|
end
|
21
22
|
|
@@ -24,17 +25,38 @@ module PuppetHerald
|
|
24
25
|
# @return [Report] created report
|
25
26
|
def create_from_yaml(yaml)
|
26
27
|
parsed = parse_yaml yaml
|
27
|
-
report =
|
28
|
+
report = nil
|
29
|
+
transaction do
|
30
|
+
report = Report.new
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
parse_properties parsed, report
|
33
|
+
parse_logs parsed, report
|
34
|
+
node = parse_node parsed, report
|
32
35
|
|
33
|
-
|
34
|
-
|
36
|
+
report.save
|
37
|
+
node.save
|
38
|
+
end
|
35
39
|
report
|
36
40
|
end
|
37
41
|
|
42
|
+
# Purges older reports then given date
|
43
|
+
#
|
44
|
+
# @param date [DateTime] a date that will be border to
|
45
|
+
# @return [Integer] number of
|
46
|
+
def purge_older_then(date)
|
47
|
+
deleted = 0
|
48
|
+
query = ['"reports"."time" < ?', date]
|
49
|
+
return 0 if where(query).count == 0
|
50
|
+
transaction do
|
51
|
+
idss = joins(:log_entries).where(query).collect(&:id).uniq
|
52
|
+
PuppetHerald::Models::LogEntry.where(['"report_id" IN (?)', idss]).delete_all unless idss.empty?
|
53
|
+
where(['"id" IN (?)', idss]).delete_all unless idss.empty?
|
54
|
+
PuppetHerald::Models::Node.delete_empty
|
55
|
+
deleted = idss.length
|
56
|
+
end
|
57
|
+
deleted
|
58
|
+
end
|
59
|
+
|
38
60
|
private
|
39
61
|
|
40
62
|
def parse_node(parsed, report)
|
@@ -42,11 +64,9 @@ module PuppetHerald
|
|
42
64
|
if node.nil?
|
43
65
|
node = Node.new
|
44
66
|
node.name = parsed.host
|
45
|
-
node.no_of_reports = 0
|
46
67
|
end
|
47
68
|
report.node = node
|
48
69
|
node.reports << report
|
49
|
-
node.no_of_reports += 1
|
50
70
|
node.status = parsed.status
|
51
71
|
node.last_run = parsed.time
|
52
72
|
node
|
@@ -62,6 +82,10 @@ module PuppetHerald
|
|
62
82
|
log = LogEntry.new
|
63
83
|
attr_to_copy = %w(level message source time)
|
64
84
|
copy_attrs in_log, log, attr_to_copy
|
85
|
+
if log.message.include?('(noop)') && report.status != 'failed'
|
86
|
+
report.status = 'pending'
|
87
|
+
parsed.status = 'pending'
|
88
|
+
end
|
65
89
|
log.report = report
|
66
90
|
report.log_entries << log
|
67
91
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
var fs = require('fs');
|
4
|
+
var wiredep = require('wiredep');
|
5
|
+
var globby = require('globby');
|
6
|
+
|
7
|
+
var cwd = '../..';
|
8
|
+
var root = fs.realpathSync(__dirname + '/' + cwd);
|
9
|
+
var publicDir = 'lib/puppet-herald/public';
|
10
|
+
var dependencies = wiredep({
|
11
|
+
cwd: publicDir,
|
12
|
+
dependencies: true,
|
13
|
+
devDependencies: false
|
14
|
+
}).js.map(function(file) {
|
15
|
+
return file.replace(root + '/', '');
|
16
|
+
});
|
17
|
+
var devDependencies = wiredep({
|
18
|
+
cwd: 'test/javascript',
|
19
|
+
dependencies: false,
|
20
|
+
devDependencies: true,
|
21
|
+
exclude: 'angular/angular.js'
|
22
|
+
}).js.map(function(file) {
|
23
|
+
return file.replace(root + '/', '');
|
24
|
+
});
|
25
|
+
var files = {
|
26
|
+
html: globby.sync([publicDir+'/**/*.html', '!**/bower_components/**']),
|
27
|
+
js: globby.sync([publicDir+'/**/*.js', '!**/bower_components/**']),
|
28
|
+
tests: globby.sync(['test/javascript/src/**/*_test.js'])
|
29
|
+
};
|
30
|
+
var search = {
|
31
|
+
coverage: publicDir + '/!(*bower_components)/**/*.js',
|
32
|
+
html2js: publicDir + '/!(*bower_components)/**/*.html'
|
33
|
+
};
|
34
|
+
var preprocessors = {};
|
35
|
+
preprocessors[search.coverage] = ['coverage'];
|
36
|
+
preprocessors[search.html2js] = ['ng-html2js'];
|
37
|
+
|
38
|
+
module.exports = {
|
39
|
+
cwd: cwd,
|
40
|
+
root: root,
|
41
|
+
publicDir: publicDir,
|
42
|
+
dependencies: dependencies,
|
43
|
+
devDependencies: devDependencies,
|
44
|
+
preprocessors: preprocessors,
|
45
|
+
files: files
|
46
|
+
};
|
@@ -2,8 +2,10 @@
|
|
2
2
|
'use strict';
|
3
3
|
|
4
4
|
var app = angular.module('herald' , [
|
5
|
-
'
|
5
|
+
'ui.router',
|
6
|
+
'herald.router',
|
6
7
|
'herald.page',
|
8
|
+
'herald.settings',
|
7
9
|
'herald.nodes',
|
8
10
|
'herald.node',
|
9
11
|
'herald.report',
|
@@ -11,17 +13,17 @@
|
|
11
13
|
'herald.artifact'
|
12
14
|
]);
|
13
15
|
|
14
|
-
app.
|
15
|
-
$
|
16
|
-
|
16
|
+
app.controller('AppController',
|
17
|
+
['Page', '$rootScope', 'Settings', '$scope',
|
18
|
+
function(Page, $rootScope, Settings, $scope) {
|
17
19
|
|
18
|
-
app.controller('AppController', ['Page', '$rootScope', function(Page, $rootScope) {
|
19
20
|
var ctrl = this;
|
20
|
-
|
21
|
-
|
21
|
+
$scope.page = null;
|
22
|
+
$scope.target = null;
|
23
|
+
$scope.settings = Settings;
|
22
24
|
$rootScope.$on('Page::titleChanged', function(event, title, target) {
|
23
|
-
|
24
|
-
|
25
|
+
$scope.page = title;
|
26
|
+
$scope.target = target;
|
25
27
|
});
|
26
28
|
}]);
|
27
29
|
|
@@ -1,13 +1,20 @@
|
|
1
1
|
{
|
2
2
|
"name": "puppet-herald",
|
3
3
|
"description": "Report processor for Puppet",
|
4
|
-
"version": "0.
|
4
|
+
"version": "0.2.0",
|
5
5
|
"homepage": "https://github.com/wavesoftware/gem-puppet-herald",
|
6
|
-
"license": "Apache
|
6
|
+
"license": "Apache-2.0",
|
7
7
|
"private": false,
|
8
8
|
"dependencies": {
|
9
9
|
"angular": "1.3.x",
|
10
|
-
"angular-
|
10
|
+
"angular-moment": "0.10.x",
|
11
|
+
"angular-ui-router": "0.2.x",
|
12
|
+
"bootstrap": "3.3.x",
|
13
|
+
"angular-utils-pagination": "0.6.x",
|
14
|
+
"angular-breadcrumb": "0.3.x",
|
15
|
+
"ngstorage": "0.3.x"
|
16
|
+
},
|
17
|
+
"devDependencies": {
|
11
18
|
"angular-loader": "1.3.x",
|
12
19
|
"angular-mocks": "1.3.x"
|
13
20
|
}
|
@@ -2,27 +2,27 @@
|
|
2
2
|
|
3
3
|
'use strict';
|
4
4
|
|
5
|
-
var module = angular.module('herald.directives.status-button', [
|
5
|
+
var module = angular.module('herald.directives.status-button', [ 'ui.router' ]);
|
6
6
|
|
7
|
-
|
7
|
+
module.controller('StatusButtonController', ['$state', '$scope', function($state, $scope) {
|
8
8
|
|
9
|
-
|
9
|
+
$scope.$state = $state;
|
10
10
|
|
11
|
-
$scope
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
this.$location.path(target);
|
11
|
+
$scope.navigate = function(route, idName, id) {
|
12
|
+
var params = {};
|
13
|
+
params[idName] = id;
|
14
|
+
this.$state.go(route, params);
|
16
15
|
};
|
17
16
|
|
18
17
|
}]);
|
19
18
|
|
20
|
-
module.directive('
|
19
|
+
module.directive('wsStatusButton', function() {
|
21
20
|
return {
|
22
21
|
restrict: 'E',
|
23
22
|
scope: {
|
24
23
|
status: '=',
|
25
24
|
id: '=',
|
25
|
+
idname: '=',
|
26
26
|
route: '='
|
27
27
|
},
|
28
28
|
controller: 'StatusButtonController',
|
@@ -39,7 +39,7 @@
|
|
39
39
|
case 'pending': return 'warning';
|
40
40
|
default: return 'default';
|
41
41
|
}
|
42
|
-
}
|
42
|
+
};
|
43
43
|
});
|
44
44
|
|
45
45
|
module.filter('iconizeStatus', function() {
|
@@ -51,6 +51,6 @@
|
|
51
51
|
case 'pending': return 'asterisk';
|
52
52
|
default: return 'sign';
|
53
53
|
}
|
54
|
-
}
|
54
|
+
};
|
55
55
|
});
|
56
56
|
})();
|