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
@@ -1,13 +1,15 @@
|
|
1
|
+
# Migration
|
1
2
|
class CreateLogEntries < ActiveRecord::Migration
|
3
|
+
# Migration
|
2
4
|
def change
|
3
5
|
create_table :log_entries do |t|
|
4
|
-
t.datetime
|
5
|
-
t.string
|
6
|
-
t.string
|
7
|
-
t.integer
|
8
|
-
t.text
|
9
|
-
|
10
|
-
t.references
|
6
|
+
t.datetime :time
|
7
|
+
t.string :level
|
8
|
+
t.string :source
|
9
|
+
t.integer :line
|
10
|
+
t.text :message
|
11
|
+
|
12
|
+
t.references :report
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
data/db/schema.rb
CHANGED
@@ -11,37 +11,35 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
15
|
-
|
14
|
+
ActiveRecord::Schema.define(version: 20_141_211_171_326) do
|
16
15
|
# These are extensions that must be enabled in order to support this database
|
17
|
-
enable_extension
|
16
|
+
enable_extension 'plpgsql'
|
18
17
|
|
19
|
-
create_table
|
20
|
-
t.datetime
|
21
|
-
t.string
|
22
|
-
t.string
|
23
|
-
t.integer
|
24
|
-
t.text
|
25
|
-
t.integer
|
18
|
+
create_table 'log_entries', force: true do |t|
|
19
|
+
t.datetime 'time'
|
20
|
+
t.string 'level'
|
21
|
+
t.string 'source'
|
22
|
+
t.integer 'line'
|
23
|
+
t.text 'message'
|
24
|
+
t.integer 'report_id'
|
26
25
|
end
|
27
26
|
|
28
|
-
create_table
|
29
|
-
t.string
|
30
|
-
t.string
|
31
|
-
t.integer
|
32
|
-
t.datetime
|
27
|
+
create_table 'nodes', force: true do |t|
|
28
|
+
t.string 'name'
|
29
|
+
t.string 'status'
|
30
|
+
t.integer 'no_of_reports'
|
31
|
+
t.datetime 'last_run'
|
33
32
|
end
|
34
33
|
|
35
|
-
create_table
|
36
|
-
t.string
|
37
|
-
t.string
|
38
|
-
t.string
|
39
|
-
t.string
|
40
|
-
t.string
|
41
|
-
t.string
|
42
|
-
t.string
|
43
|
-
t.datetime
|
44
|
-
t.integer
|
34
|
+
create_table 'reports', force: true do |t|
|
35
|
+
t.string 'status'
|
36
|
+
t.string 'environment'
|
37
|
+
t.string 'transaction_uuid'
|
38
|
+
t.string 'configuration_version'
|
39
|
+
t.string 'puppet_version'
|
40
|
+
t.string 'kind'
|
41
|
+
t.string 'host'
|
42
|
+
t.datetime 'time'
|
43
|
+
t.integer 'node_id'
|
45
44
|
end
|
46
|
-
|
47
45
|
end
|
data/lib/puppet-herald.rb
CHANGED
@@ -1,49 +1,87 @@
|
|
1
1
|
begin
|
2
2
|
require 'pry'
|
3
|
-
rescue LoadError
|
3
|
+
rescue LoadError # rubocop:disable Lint/HandleExceptions
|
4
4
|
# Do nothing here
|
5
5
|
end
|
6
6
|
|
7
|
+
require 'puppet-herald/database'
|
8
|
+
|
9
|
+
# A module for Herald
|
7
10
|
module PuppetHerald
|
11
|
+
@root = File.dirname(File.dirname(File.realpath(__FILE__)))
|
12
|
+
@database = PuppetHerald::Database.new
|
8
13
|
|
9
|
-
|
14
|
+
# A database object
|
15
|
+
# @return [PuppetHerald::Database] a database object
|
16
|
+
def self.database # rubocop:disable Style/TrivialAccessors
|
17
|
+
@database
|
18
|
+
end
|
10
19
|
|
11
|
-
|
12
|
-
|
20
|
+
# Calculates a replative directory inside the project
|
21
|
+
#
|
22
|
+
# @param dir [String] a sub directory
|
23
|
+
# @return [String] a full path to replative dir
|
24
|
+
def self.relative_dir(dir)
|
25
|
+
File.realpath(File.join @root, dir)
|
13
26
|
end
|
14
27
|
|
28
|
+
def self.environment=(environment)
|
29
|
+
rackenv = :production
|
30
|
+
envsymbol = environment.to_s.to_sym
|
31
|
+
case envsymbol
|
32
|
+
when :dev, :development
|
33
|
+
rackenv = :development
|
34
|
+
when :test, :ci
|
35
|
+
rackenv = :test
|
36
|
+
else
|
37
|
+
rackenv = :production
|
38
|
+
envsymbol = :production
|
39
|
+
end
|
40
|
+
ENV['PUPPET_HERALD_ENV'] = envsymbol.to_s
|
41
|
+
ENV['RACK_ENV'] = rackenv.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets the environment set for Herald
|
45
|
+
# @return [Symbol] an environment
|
15
46
|
def self.environment
|
16
47
|
env = :production
|
17
|
-
unless ENV['PUPPET_HERALD_ENV'].nil?
|
18
|
-
|
19
|
-
|
20
|
-
return env
|
48
|
+
env = ENV['PUPPET_HERALD_ENV'].to_sym unless ENV['PUPPET_HERALD_ENV'].nil?
|
49
|
+
ENV['RACK_ENV'] = env.to_s
|
50
|
+
env
|
21
51
|
end
|
22
52
|
|
23
|
-
|
24
|
-
|
53
|
+
# Checks is running in DEVELOPMENT kind of environment (dev, ci, test)
|
54
|
+
#
|
55
|
+
# @return [Boolean] true if runs in development
|
56
|
+
def self.in_dev?
|
57
|
+
[:development, :dev, :test, :ci].include? environment
|
25
58
|
end
|
26
59
|
|
27
|
-
|
28
|
-
|
60
|
+
# Checks is running in production environment
|
61
|
+
#
|
62
|
+
# @return [Boolean] true if runs in production
|
63
|
+
def self.in_prod?
|
64
|
+
!in_dev?
|
29
65
|
end
|
30
66
|
|
31
|
-
|
67
|
+
# Reports a bug in desired format
|
68
|
+
#
|
69
|
+
# @param ex [Exception] an exception that was thrown
|
70
|
+
# @return [Hash] a hash with info about bug to be displayed to user
|
71
|
+
def self.bug(ex)
|
32
72
|
file = Tempfile.new(['puppet-herald-bug', '.log'])
|
33
73
|
filepath = file.path
|
34
74
|
file.close
|
35
75
|
file.unlink
|
36
|
-
message = "v#{PuppetHerald::VERSION}-#{ex.class
|
76
|
+
message = "v#{PuppetHerald::VERSION}-#{ex.class}: #{ex.message}"
|
37
77
|
contents = message + "\n\n" + ex.backtrace.join("\n") + "\n"
|
38
78
|
File.write(filepath, contents)
|
39
79
|
bugo = {
|
40
|
-
:
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
80
|
+
message: message,
|
81
|
+
homepage: PuppetHerald::HOMEPAGE,
|
82
|
+
bugfile: filepath,
|
83
|
+
help: "Please report this bug to #{PuppetHerald::HOMEPAGE} by passing contents of bug file: #{filepath}"
|
44
84
|
}
|
45
|
-
|
85
|
+
bugo
|
46
86
|
end
|
47
87
|
end
|
48
|
-
|
49
|
-
require 'puppet-herald/database'
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/namespace'
|
3
|
+
require 'puppet-herald'
|
4
|
+
require 'puppet-herald/app/configuration'
|
5
|
+
require 'puppet-herald/models/node'
|
6
|
+
require 'puppet-herald/models/report'
|
7
|
+
|
8
|
+
# A module for Herald
|
9
|
+
module PuppetHerald
|
10
|
+
# Module that holds modules of Sinatra app
|
11
|
+
module App
|
12
|
+
# An implementation of API v1
|
13
|
+
class ApiImplV1
|
14
|
+
# Constructor
|
15
|
+
# @param app [Sinatra::Base] an app module
|
16
|
+
# @return [ApiImplV1] an API impl
|
17
|
+
def initialize(app)
|
18
|
+
@app = app
|
19
|
+
end
|
20
|
+
# Creates a new report
|
21
|
+
# @param request [Sinatra::Request] an request object
|
22
|
+
# @return [Array] an response array: [code, body] or [code, headers, body]
|
23
|
+
def post_reports(request)
|
24
|
+
yaml = request.body.read
|
25
|
+
report = PuppetHerald::Models::Report.create_from_yaml yaml
|
26
|
+
body = { id: report.id }.to_json
|
27
|
+
[201, body]
|
28
|
+
end
|
29
|
+
# Get a report by its ID
|
30
|
+
# @param params [Hash] an requests parsed params
|
31
|
+
# @return [Array] an response array: [code, body] or [code, headers, body]
|
32
|
+
def get_report(params)
|
33
|
+
id = params[:id]
|
34
|
+
report = PuppetHerald::Models::Report.get_with_log_entries(id)
|
35
|
+
status = 200
|
36
|
+
status = 404 if report.nil?
|
37
|
+
body = report.to_json(include: :log_entries)
|
38
|
+
[status, body]
|
39
|
+
end
|
40
|
+
# Gets all nodes
|
41
|
+
# @return [Array] an response array: [code, body] or [code, headers, body]
|
42
|
+
def nodes
|
43
|
+
nodes = PuppetHerald::Models::Node.all
|
44
|
+
[200, nodes.to_json]
|
45
|
+
end
|
46
|
+
# Gets a node by its ID
|
47
|
+
# @param params [Hash] an requests parsed params
|
48
|
+
# @return [Array] an response array: [code, body] or [code, headers, body]
|
49
|
+
def get_node(params)
|
50
|
+
id = params[:id]
|
51
|
+
node = PuppetHerald::Models::Node.get_with_reports(id)
|
52
|
+
status = 200
|
53
|
+
status = 404 if node.nil?
|
54
|
+
body = node.to_json(include: :reports)
|
55
|
+
[status, body]
|
56
|
+
end
|
57
|
+
# Get a app's artifact information
|
58
|
+
# @return [Array] an response array: [code, body] or [code, headers, body]
|
59
|
+
def version_json
|
60
|
+
ver = {}
|
61
|
+
[:VERSION, :LICENSE, :NAME, :PACKAGE, :SUMMARY, :DESCRIPTION, :HOMEPAGE].each do |const|
|
62
|
+
ver[const.downcase] = PuppetHerald.const_get const
|
63
|
+
end
|
64
|
+
[200, ver.to_json]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# An API app module
|
69
|
+
class Api < Sinatra::Base
|
70
|
+
register Sinatra::Namespace
|
71
|
+
use PuppetHerald::App::Configuration
|
72
|
+
set :api, ApiImplV1.new(self)
|
73
|
+
helpers do
|
74
|
+
# API getter
|
75
|
+
# @return [ApiImplV1] an api object
|
76
|
+
def api
|
77
|
+
settings.api
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
get '/version.json' do
|
82
|
+
content_type 'application/json'
|
83
|
+
api.version_json
|
84
|
+
end
|
85
|
+
|
86
|
+
namespace '/api' do
|
87
|
+
namespace '/v1' do
|
88
|
+
post '/reports' do
|
89
|
+
content_type 'application/json'
|
90
|
+
api.post_reports request
|
91
|
+
end
|
92
|
+
|
93
|
+
get '/nodes' do
|
94
|
+
content_type 'application/json'
|
95
|
+
api.nodes
|
96
|
+
end
|
97
|
+
|
98
|
+
get '/nodes/:id' do
|
99
|
+
content_type 'application/json'
|
100
|
+
api.get_node params
|
101
|
+
end
|
102
|
+
|
103
|
+
get '/reports/:id' do
|
104
|
+
content_type 'application/json'
|
105
|
+
api.get_report params
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'sinatra/namespace'
|
4
|
+
require 'sinatra/activerecord'
|
5
|
+
require 'puppet-herald'
|
6
|
+
require 'puppet-herald/javascript'
|
7
|
+
|
8
|
+
# A module for Herald
|
9
|
+
module PuppetHerald
|
10
|
+
# A module that holds module of app
|
11
|
+
module App
|
12
|
+
# A configuration for application
|
13
|
+
class Configuration < Sinatra::Base
|
14
|
+
register Sinatra::ActiveRecordExtension
|
15
|
+
|
16
|
+
set :database, PuppetHerald.database.spec unless PuppetHerald.database.spec.nil?
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# Migrates a database to state desired for the application
|
20
|
+
#
|
21
|
+
# @return [nil]
|
22
|
+
def dbmigrate!
|
23
|
+
ActiveRecord::Base.establish_connection(PuppetHerald.database.spec)
|
24
|
+
setup_database_logger
|
25
|
+
ActiveRecord::Migrator.up 'db/migrate'
|
26
|
+
ActiveRecord::Base.clear_active_connections!
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Is request part of the API
|
31
|
+
# @param req [Sinatra::Request] a request to check
|
32
|
+
# @return [Boolean] true, if given request point to part of the API
|
33
|
+
def api?(req)
|
34
|
+
(req.path.start_with?('/api') || req.path.start_with?('/version.json'))
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Sets logger level for database handlers
|
40
|
+
#
|
41
|
+
# @return [nil]
|
42
|
+
def setup_database_logger
|
43
|
+
if PuppetHerald.in_dev?
|
44
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
45
|
+
else
|
46
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if PuppetHerald.in_dev?
|
53
|
+
set :environment, :development
|
54
|
+
else
|
55
|
+
set :environment, :production
|
56
|
+
end
|
57
|
+
set :show_exceptions, false
|
58
|
+
|
59
|
+
error do
|
60
|
+
@bug = PuppetHerald.bug env['sinatra.error']
|
61
|
+
if PuppetHerald::App::Configuration.api? request
|
62
|
+
content_type 'application/json'
|
63
|
+
@bug.to_json
|
64
|
+
else
|
65
|
+
erb :err500
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'puppet-herald'
|
2
|
+
require 'puppet-herald/javascript'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'sinatra/namespace'
|
5
|
+
|
6
|
+
# A module for Herald
|
7
|
+
module PuppetHerald
|
8
|
+
# A module that holds module of app
|
9
|
+
module App
|
10
|
+
# Frontend logic impl internal class
|
11
|
+
class LogicImpl
|
12
|
+
def initialize
|
13
|
+
@js = PuppetHerald::Javascript.new
|
14
|
+
end
|
15
|
+
# Gets an app.html
|
16
|
+
# @dodgy executed also to raise an exception for testing (application_spec)
|
17
|
+
def app_html
|
18
|
+
if PuppetHerald.in_prod?
|
19
|
+
minified = '.min'
|
20
|
+
files = ['/app.min.js']
|
21
|
+
else
|
22
|
+
minified = ''
|
23
|
+
files = @js.files
|
24
|
+
end
|
25
|
+
[minified, files]
|
26
|
+
end
|
27
|
+
# Uglify an application JS's into one minified JS file
|
28
|
+
# @param mapname [String] name of source map to be put into uglified JS
|
29
|
+
# @return [Hash] a hash with uglified JS and source map
|
30
|
+
def uglify(mapname)
|
31
|
+
@js.uglify mapname
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# Class that holds implementation of frontent interface
|
35
|
+
class Frontend < Sinatra::Base
|
36
|
+
use PuppetHerald::App::Configuration
|
37
|
+
set :logic, PuppetHerald::App::LogicImpl.new
|
38
|
+
|
39
|
+
get '/' do
|
40
|
+
redirect '/app.html', 301
|
41
|
+
end
|
42
|
+
|
43
|
+
get '/index.html' do
|
44
|
+
redirect '/app.html', 301
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/app.html' do
|
48
|
+
cache_control :public, :must_revalidate, max_age: 60 if PuppetHerald.in_prod?
|
49
|
+
@minified, @files = settings.logic.app_html
|
50
|
+
erb :app
|
51
|
+
end
|
52
|
+
|
53
|
+
get(/\/app\.min\.(js\.map|js)/) do |ext|
|
54
|
+
content_type 'application/javascript'
|
55
|
+
contents = settings.logic.uglify('/app.min.js.map')[ext]
|
56
|
+
cache_control :public, :must_revalidate, max_age: 60 if PuppetHerald.in_prod?
|
57
|
+
contents
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
-
|
3
|
-
|
4
|
-
<!--[if IE 8]> <html lang="en" ng-app="herald" class="no-js lt-ie9"> <![endif]-->
|
5
|
-
<!--[if gt IE 8]><!--> <html lang="en" ng-app="herald" class="no-js"> <!--<![endif]-->
|
6
|
-
<head ng-controller="AppController as app">
|
2
|
+
<html lang="en" ng-app="herald" ng-controller="AppController">
|
3
|
+
<head>
|
7
4
|
<meta charset="utf-8">
|
8
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
9
6
|
<title>Herald - a Puppet report processor</title>
|
@@ -20,7 +17,7 @@
|
|
20
17
|
|
21
18
|
<section class="container-fluid">
|
22
19
|
|
23
|
-
<h2><img src="/img/shield97.svg" />Herald <small>a Puppet report processor</small></h2>
|
20
|
+
<h2><a href="#/"><img src="/img/shield97.svg" />Herald</a> <small>a Puppet report processor</small></h2>
|
24
21
|
|
25
22
|
<div ng-view></div>
|
26
23
|
|
@@ -32,8 +29,8 @@
|
|
32
29
|
|
33
30
|
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular<%= @minified %>.js"></script>
|
34
31
|
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-route<%= @minified %>.js"></script>
|
35
|
-
<script src="//cdn.jsdelivr.net/momentjs/2.
|
36
|
-
<script src="//cdn.jsdelivr.net/angular.moment/0.
|
32
|
+
<script src="//cdn.jsdelivr.net/momentjs/2.8.4/moment.min.js"></script>
|
33
|
+
<script src="//cdn.jsdelivr.net/angular.moment/0.8.3/angular-moment<%= @minified %>.js"></script>
|
37
34
|
|
38
35
|
<!-- Automatic incudes of project files -->
|
39
36
|
<% @files.each do |file| %>
|