puppet-herald 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,8 +1,5 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
-
|
3
|
-
<!--[if IE 7]> <html lang="en" class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
4
|
-
<!--[if IE 8]> <html lang="en" class="no-js lt-ie9"> <![endif]-->
|
5
|
-
<!--[if gt IE 8]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
|
2
|
+
<html lang="en">
|
6
3
|
<head>
|
7
4
|
<meta charset="utf-8">
|
8
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
require 'puppet-herald/app/configuration'
|
4
|
+
require 'puppet-herald/app/api'
|
5
|
+
require 'puppet-herald/app/frontend'
|
6
|
+
|
7
|
+
# A module for Herald
|
8
|
+
module PuppetHerald
|
9
|
+
# Class for an Herald sinatra application
|
10
|
+
class Application < Sinatra::Application
|
11
|
+
use PuppetHerald::App::Configuration
|
12
|
+
use PuppetHerald::App::Frontend
|
13
|
+
use PuppetHerald::App::Api
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Executes the Herald application
|
17
|
+
#
|
18
|
+
# @param options [Hash] an extra options for Rack server
|
19
|
+
# @param block [block] an extra configuration block
|
20
|
+
# @return [Sinatra::Application] an Herald application
|
21
|
+
def run!(options = {}, &block)
|
22
|
+
PuppetHerald::App::Configuration.dbmigrate!
|
23
|
+
super options, *block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/puppet-herald/cli.rb
CHANGED
@@ -4,77 +4,98 @@ require 'puppet-herald'
|
|
4
4
|
require 'puppet-herald/version'
|
5
5
|
require 'puppet-herald/database'
|
6
6
|
|
7
|
+
# A module for Herald
|
7
8
|
module PuppetHerald
|
9
|
+
# A CLI class
|
8
10
|
class CLI
|
11
|
+
# Initialize CLI
|
12
|
+
# @return [CLI] an CLI object
|
13
|
+
def initialize
|
14
|
+
@logger = Logger.new STDOUT
|
15
|
+
@errlogger = Logger.new STDERR
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logger for CLI interface (error and std)
|
20
|
+
# @return [Logger] logger for CLI
|
21
|
+
attr_reader :logger, :errlogger
|
9
22
|
|
10
|
-
|
11
|
-
|
12
|
-
|
23
|
+
# Executes an Herald app from CLI
|
24
|
+
#
|
25
|
+
# @param argv [Array] an argv from CLI
|
26
|
+
# @return [Integer] a status code for program
|
27
|
+
def run!(argv = ARGV)
|
28
|
+
PuppetHerald.environment
|
13
29
|
|
14
|
-
|
15
|
-
|
30
|
+
options = parse_or_kill argv, 2
|
31
|
+
run_or_kill options, 1
|
32
|
+
Kernel.exit 0
|
16
33
|
end
|
17
34
|
|
18
|
-
|
19
|
-
|
35
|
+
protected
|
36
|
+
|
37
|
+
# Parse an ARGV command line arguments
|
38
|
+
# @param argv [Array] an argv from CLI
|
39
|
+
# @return [Hash] options to use by application
|
40
|
+
def parse(argv)
|
41
|
+
options = parser.process!(argv)
|
42
|
+
|
43
|
+
logger.info "Starting #{PuppetHerald::NAME} v#{PuppetHerald::VERSION} in #{PuppetHerald.environment}..."
|
44
|
+
PuppetHerald.database.dbconn = options[:dbconn]
|
45
|
+
PuppetHerald.database.passfile = options[:passfile]
|
46
|
+
PuppetHerald.database.spec(true)
|
47
|
+
options
|
20
48
|
end
|
21
49
|
|
22
|
-
|
23
|
-
|
50
|
+
private
|
51
|
+
|
52
|
+
def run_or_kill(options, retcode)
|
53
|
+
require 'puppet-herald/application'
|
54
|
+
PuppetHerald::Application.run! options
|
55
|
+
rescue StandardError => ex
|
56
|
+
bug = PuppetHerald.bug(ex)
|
57
|
+
errlogger.fatal "Unexpected error occured, mayby a bug?\n\n#{bug[:message]}\n\n#{bug[:help]}"
|
58
|
+
Kernel.exit retcode
|
24
59
|
end
|
25
60
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
PuppetHerald::App.run! options
|
32
|
-
rescue Exception => ex
|
33
|
-
bug = PuppetHerald.bug(ex)
|
34
|
-
errlogger.fatal "Unexpected error occured, mayby a bug?\n\n#{bug[:message]}\n\n#{bug[:help]}"
|
35
|
-
self.retcode = 1
|
36
|
-
end
|
37
|
-
Kernel::exit @@retcode
|
61
|
+
def parse_or_kill(argv, retcode)
|
62
|
+
return parse argv
|
63
|
+
rescue StandardError => ex
|
64
|
+
errlogger.fatal "Database configuration is invalid!\n\n#{ex.message}"
|
65
|
+
Kernel.exit retcode
|
38
66
|
end
|
39
67
|
|
40
|
-
def
|
41
|
-
|
42
|
-
banner = <<-eos
|
68
|
+
def banner
|
69
|
+
txt = <<-eos
|
43
70
|
#{PuppetHerald::NAME} v#{PuppetHerald::VERSION} - #{PuppetHerald::SUMMARY}
|
44
71
|
|
45
72
|
#{PuppetHerald::DESCRIPTION}
|
46
73
|
|
47
|
-
Usage: #{$
|
74
|
+
Usage: #{$PROGRAM_NAME} [options]
|
48
75
|
|
49
76
|
For --dbconn option you can use both PostgreSQL and SQLite3 (postgresql://host/db, sqlite://file/path).
|
50
77
|
CAUTION! For security reasons, don't pass password in connection string, use --passfile option!
|
51
78
|
|
52
79
|
eos
|
80
|
+
txt
|
81
|
+
end
|
82
|
+
|
83
|
+
def parser
|
53
84
|
home = File.expand_path('~')
|
54
85
|
defaultdb = "sqlite://#{home}/pherald.db"
|
55
86
|
defaultdbpass = "#{home}/.pherald.pass"
|
56
|
-
|
87
|
+
Parser.new do |p|
|
57
88
|
p.banner = banner
|
58
89
|
p.version = PuppetHerald::VERSION
|
59
|
-
p.option :bind,
|
60
|
-
p.option :port,
|
61
|
-
p.option :dbconn,
|
62
|
-
p.option
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
PuppetHerald::Database.dbconn = options[:dbconn]
|
68
|
-
PuppetHerald::Database.passfile = options[:passfile]
|
69
|
-
begin
|
70
|
-
PuppetHerald::Database.spec :echo => true
|
71
|
-
rescue Exception => ex
|
72
|
-
errlogger.fatal "Database configuration is invalid!\n\n#{ex.message}"
|
73
|
-
self.retcode = 2
|
74
|
-
raise ex
|
90
|
+
p.option :bind, 'Hostname to bind to', default: 'localhost'
|
91
|
+
p.option :port, 'Port to use', default: 11_303, value_satisfies: ->(x) { x >= 1 && x <= 65_535 }
|
92
|
+
p.option :dbconn, 'Connection string to database, see info above', default: defaultdb
|
93
|
+
p.option(
|
94
|
+
:passfile,
|
95
|
+
'If using postgresql, this file will be read for password to database',
|
96
|
+
default: defaultdbpass
|
97
|
+
)
|
75
98
|
end
|
76
|
-
|
77
|
-
return options
|
78
99
|
end
|
79
100
|
end
|
80
|
-
end
|
101
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
# A module for Herald
|
4
|
+
module PuppetHerald
|
5
|
+
# A client class for Herald
|
6
|
+
class Client
|
7
|
+
# Constructs a client
|
8
|
+
#
|
9
|
+
# @param host [String] a host to connect to, default to +'localhost'+
|
10
|
+
# @param port [Integer] a port to connect to, default to +11303+
|
11
|
+
# @return [PuppetHerald::Client] a client instance
|
12
|
+
def initialize(host = 'localhost', port = 11_303)
|
13
|
+
@host = host
|
14
|
+
@port = port
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Process a puppet report and sends it to Herald
|
19
|
+
#
|
20
|
+
# @param report [Puppet::Transaction::Report] a puppet report
|
21
|
+
# @param block [Proc] a optional block that can modify request before sending
|
22
|
+
# @return [Boolean] true if everything is ok
|
23
|
+
def process(report, &block)
|
24
|
+
path = '/api/v1/reports'
|
25
|
+
header = { 'Content-Type' => 'application/yaml' }
|
26
|
+
req = Net::HTTP::Post.new(path, initheader = header) # rubocop:disable all
|
27
|
+
req.body = report.to_yaml
|
28
|
+
block.call(req) if block
|
29
|
+
Net::HTTP.new(@host, @port).start { |http| http.request(req) }
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,57 +1,101 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'logger'
|
3
3
|
|
4
|
+
# A module for Herald
|
4
5
|
module PuppetHerald
|
6
|
+
# A class for a database configuration
|
5
7
|
class Database
|
8
|
+
def initialize
|
9
|
+
@dbconn = nil
|
10
|
+
@passfile = nil
|
11
|
+
@logger = Logger.new STDOUT
|
12
|
+
end
|
13
|
+
|
14
|
+
# Gets a logger for database
|
15
|
+
# @return [Logger] a logger
|
16
|
+
attr_reader :logger
|
17
|
+
|
18
|
+
# Sets a database connection
|
19
|
+
# @return [String] a dbconnection string
|
20
|
+
attr_writer :dbconn
|
6
21
|
|
7
|
-
|
8
|
-
|
9
|
-
|
22
|
+
# Sets a passfile
|
23
|
+
# @return [String] a password file
|
24
|
+
attr_writer :passfile
|
10
25
|
|
11
|
-
|
12
|
-
|
26
|
+
# Compiles a spec for database creation
|
27
|
+
#
|
28
|
+
# @param log [Boolean] should log on screen?
|
29
|
+
# @return [Hash] a database configuration
|
30
|
+
def spec(log = false)
|
31
|
+
connection = process_spec
|
32
|
+
print_config(connection, log)
|
33
|
+
connection
|
13
34
|
end
|
14
35
|
|
15
|
-
|
16
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
def process_spec
|
39
|
+
match = validate_conn(@dbconn)
|
40
|
+
if %w(sqlite sqlite3).include? match[1]
|
41
|
+
connection = sqlite(match)
|
42
|
+
else
|
43
|
+
connection = postgresql(@dbconn, @passfile)
|
44
|
+
end
|
45
|
+
connection
|
17
46
|
end
|
18
47
|
|
19
|
-
def
|
20
|
-
|
48
|
+
def validate_conn(dbconn)
|
49
|
+
fail 'Connection is not set, can not validate database connection' if dbconn.nil?
|
50
|
+
match = dbconn.match(%r{^(sqlite3?|postgres(?:ql)?)://(.+)$})
|
51
|
+
|
52
|
+
fail "Invalid database connection string given: #{dbconn}" if match.nil?
|
53
|
+
match
|
54
|
+
end
|
55
|
+
|
56
|
+
def print_config(connection, log)
|
57
|
+
return unless log
|
58
|
+
copy = connection.dup
|
59
|
+
copy[:password] = '***' unless copy[:password].nil?
|
60
|
+
logger.info "Using #{copy.inspect} for database."
|
21
61
|
end
|
22
62
|
|
23
|
-
def
|
24
|
-
return nil if @@dbconn.nil?
|
63
|
+
def sqlite(match)
|
25
64
|
connection = {}
|
26
|
-
|
27
|
-
unless match
|
28
|
-
|
29
|
-
|
30
|
-
if ['sqlite', 'sqlite3'].include? match[1]
|
31
|
-
dbname = match[2]
|
32
|
-
unless dbname.match /^(?:file:)?:mem/
|
33
|
-
dbname = File.expand_path(dbname)
|
34
|
-
FileUtils.touch dbname
|
35
|
-
end
|
36
|
-
connection[:adapter] = 'sqlite3'
|
37
|
-
connection[:database] = dbname
|
38
|
-
else
|
39
|
-
db = URI.parse @@dbconn
|
40
|
-
dbname = db.path[1..-1]
|
41
|
-
connection[:adapter] = db.scheme == 'postgres' ? 'postgresql' : db.scheme
|
42
|
-
connection[:host] = db.host
|
43
|
-
connection[:port] = db.port unless db.port.nil?
|
44
|
-
connection[:username] = db.user.nil? ? dbname : db.user
|
45
|
-
connection[:password] = File.read(@@passfile).strip
|
46
|
-
connection[:database] = dbname
|
47
|
-
connection[:encoding] = 'utf8'
|
65
|
+
dbname = match[2]
|
66
|
+
unless dbname.match(/^(?:file:)?:mem/)
|
67
|
+
dbname = File.expand_path(dbname)
|
68
|
+
FileUtils.touch dbname
|
48
69
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
70
|
+
connection[:adapter] = 'sqlite3'
|
71
|
+
connection[:database] = dbname
|
72
|
+
connection
|
73
|
+
end
|
74
|
+
|
75
|
+
def postgresql(conn, passfile)
|
76
|
+
connection = {}
|
77
|
+
db = URI.parse conn
|
78
|
+
dbname = db.path[1..-1]
|
79
|
+
connection[:adapter] = pgscheme(db.scheme)
|
80
|
+
connection[:host] = db.host
|
81
|
+
connection[:username] = pguser(db.user, dbname)
|
82
|
+
connection[:password] = File.read(passfile).strip
|
83
|
+
connection[:database] = dbname
|
84
|
+
connection[:encoding] = 'utf8'
|
85
|
+
pgport(connection, db.port)
|
86
|
+
connection
|
87
|
+
end
|
88
|
+
|
89
|
+
def pgport(connection, port)
|
90
|
+
connection[:port] = port unless port.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def pgscheme(scheme)
|
94
|
+
scheme == 'postgres' ? 'postgresql' : scheme
|
95
|
+
end
|
96
|
+
|
97
|
+
def pguser(user, dbname)
|
98
|
+
user.nil? ? dbname : user
|
55
99
|
end
|
56
100
|
end
|
57
|
-
end
|
101
|
+
end
|
@@ -1,34 +1,40 @@
|
|
1
1
|
require 'puppet-herald'
|
2
2
|
require 'uglifier'
|
3
3
|
|
4
|
+
# A module for Herald
|
4
5
|
module PuppetHerald
|
6
|
+
# A javascript processing class
|
5
7
|
class Javascript
|
8
|
+
# Initialize JS class
|
9
|
+
def initialize
|
10
|
+
@files = nil
|
11
|
+
@base = 'lib/puppet-herald/public'
|
12
|
+
end
|
6
13
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@@files = nil
|
14
|
-
end
|
15
|
-
if @@files.nil?
|
16
|
-
public_dir = PuppetHerald::relative_dir(@@base)
|
14
|
+
# Returns a list of JS files to be inserted into main HTML
|
15
|
+
# @return [Array] list of JS's
|
16
|
+
def files
|
17
|
+
@files = nil if PuppetHerald.in_dev?
|
18
|
+
if @files.nil?
|
19
|
+
public_dir = PuppetHerald.relative_dir(@base)
|
17
20
|
all = Dir.chdir(public_dir) { Dir.glob('**/*.js') }
|
18
|
-
|
21
|
+
@files = all.reverse.reject { |file| file.match(/_test\.js$/) }
|
19
22
|
end
|
20
|
-
|
23
|
+
@files
|
21
24
|
end
|
22
25
|
|
23
|
-
|
24
|
-
|
26
|
+
# Uglify an application JS's into one minified JS file
|
27
|
+
# @param mapname [String] name of source map to be put into uglified JS
|
28
|
+
# @return [Hash] a hash with uglified JS and source map
|
29
|
+
def uglify(mapname)
|
30
|
+
sources = files.collect { |file| File.read("#{@base}/#{file}") }
|
25
31
|
source = sources.join "\n"
|
26
|
-
uglifier = Uglifier.new(:
|
32
|
+
uglifier = Uglifier.new(source_map_url: mapname)
|
27
33
|
uglified, source_map = uglifier.compile_with_map(source)
|
28
|
-
|
34
|
+
{
|
29
35
|
'js' => uglified,
|
30
36
|
'js.map' => source_map
|
31
37
|
}
|
32
38
|
end
|
33
39
|
end
|
34
|
-
end
|
40
|
+
end
|
@@ -1,7 +1,17 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# A module for Herald
|
2
|
+
module PuppetHerald
|
3
|
+
# module for models
|
4
|
+
module Models
|
5
|
+
# A node model
|
6
|
+
class Node < ActiveRecord::Base
|
7
|
+
has_many :reports, dependent: :delete_all
|
3
8
|
|
4
|
-
|
5
|
-
|
9
|
+
# Gets a node with prefetched reports
|
10
|
+
# @param id [Integer] a in of node to get
|
11
|
+
# @return [Node, nil] fetched node or nil
|
12
|
+
def self.get_with_reports(id)
|
13
|
+
Node.joins(:reports).includes(:reports).find_by_id(id)
|
14
|
+
end
|
15
|
+
end
|
6
16
|
end
|
7
|
-
end
|
17
|
+
end
|