lbrt 0.1.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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +180 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/lbrt +15 -0
- data/lbrt.gemspec +31 -0
- data/lib/lbrt.rb +46 -0
- data/lib/lbrt/alert.rb +91 -0
- data/lib/lbrt/alert/dsl.rb +9 -0
- data/lib/lbrt/alert/dsl/context.rb +32 -0
- data/lib/lbrt/alert/dsl/context/alert.rb +75 -0
- data/lib/lbrt/alert/dsl/context/alert/condition.rb +61 -0
- data/lib/lbrt/alert/dsl/converter.rb +113 -0
- data/lib/lbrt/alert/exporter.rb +38 -0
- data/lib/lbrt/cli.rb +2 -0
- data/lib/lbrt/cli/alert.rb +26 -0
- data/lib/lbrt/cli/app.rb +15 -0
- data/lib/lbrt/cli/service.rb +26 -0
- data/lib/lbrt/cli/space.rb +27 -0
- data/lib/lbrt/driver.rb +240 -0
- data/lib/lbrt/ext/string_ext.rb +25 -0
- data/lib/lbrt/logger.rb +32 -0
- data/lib/lbrt/service.rb +73 -0
- data/lib/lbrt/service/dsl.rb +9 -0
- data/lib/lbrt/service/dsl/context.rb +33 -0
- data/lib/lbrt/service/dsl/context/service.rb +32 -0
- data/lib/lbrt/service/dsl/converter.rb +38 -0
- data/lib/lbrt/service/exporter.rb +37 -0
- data/lib/lbrt/space.rb +126 -0
- data/lib/lbrt/space/dsl.rb +9 -0
- data/lib/lbrt/space/dsl/context.rb +29 -0
- data/lib/lbrt/space/dsl/context/space.rb +19 -0
- data/lib/lbrt/space/dsl/context/space/chart.rb +44 -0
- data/lib/lbrt/space/dsl/context/space/chart/stream.rb +48 -0
- data/lib/lbrt/space/dsl/converter.rb +107 -0
- data/lib/lbrt/space/exporter.rb +56 -0
- data/lib/lbrt/utils.rb +64 -0
- data/lib/lbrt/version.rb +3 -0
- metadata +202 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
class String
|
2
|
+
@@colorize = false
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def colorize=(value)
|
6
|
+
@@colorize = value
|
7
|
+
end
|
8
|
+
|
9
|
+
def colorize
|
10
|
+
@@colorize
|
11
|
+
end
|
12
|
+
end # of class methods
|
13
|
+
|
14
|
+
Term::ANSIColor::Attribute.named_attributes.map do |attribute|
|
15
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
16
|
+
def #{attribute.name}
|
17
|
+
if @@colorize
|
18
|
+
Term::ANSIColor.send(#{attribute.name.inspect}, self)
|
19
|
+
else
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
EOS
|
24
|
+
end
|
25
|
+
end
|
data/lib/lbrt/logger.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class Lbrt::Logger < ::Logger
|
2
|
+
include Singleton
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
super($stdout)
|
6
|
+
|
7
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
8
|
+
"#{msg}\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
self.level = INFO
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_debug(value)
|
15
|
+
self.level = value ? DEBUG : INFO
|
16
|
+
end
|
17
|
+
|
18
|
+
module Helper
|
19
|
+
def log(level, message, opts = {})
|
20
|
+
global_options = (@options || {}).dup
|
21
|
+
global_options.delete(:color)
|
22
|
+
opts = global_options.merge(opts)
|
23
|
+
|
24
|
+
message = "[#{level.to_s.upcase}] #{message}" unless level == :info
|
25
|
+
message << ' (dry-run)' if opts[:dry_run]
|
26
|
+
message = message.send(opts[:color]) if opts[:color]
|
27
|
+
|
28
|
+
logger = opts[:logger] || Lbrt::Logger.instance
|
29
|
+
logger.send(level, message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/lbrt/service.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
class Lbrt::Service
|
2
|
+
include Lbrt::Logger::Helper
|
3
|
+
|
4
|
+
def initialize(client, options = {})
|
5
|
+
@client = client
|
6
|
+
@options = options
|
7
|
+
@driver = Lbrt::Driver.new(@client, @options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def export(export_options = {})
|
11
|
+
exported = Lbrt::Service::Exporter.export(@client, @options)
|
12
|
+
Lbrt::Service::DSL.convert(exported, @options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def apply(file)
|
16
|
+
walk(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def walk(file)
|
22
|
+
expected = load_file(file)
|
23
|
+
actual = Lbrt::Service::Exporter.export(@client, @options)
|
24
|
+
walk_services(expected, actual)
|
25
|
+
end
|
26
|
+
|
27
|
+
def walk_services(expected, actual)
|
28
|
+
updated = false
|
29
|
+
|
30
|
+
expected.each do |key, expected_service|
|
31
|
+
next unless key.any? {|i| Lbrt::Utils.matched?(i, @options[:target]) }
|
32
|
+
actual_service = actual.delete(key)
|
33
|
+
|
34
|
+
if actual_service
|
35
|
+
updated = walk_service(key, expected_service, actual_service) || updated
|
36
|
+
else
|
37
|
+
updated = @driver.create_service(key, expected_service) || updated
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
actual.each do |key, actual_service|
|
42
|
+
next unless key.any? {|i| Lbrt::Utils.matched?(i, @options[:target]) }
|
43
|
+
updated = @driver.delete_service(key, actual_service) || updated
|
44
|
+
end
|
45
|
+
|
46
|
+
updated
|
47
|
+
end
|
48
|
+
|
49
|
+
def walk_service(key, expected, actual)
|
50
|
+
updated = false
|
51
|
+
|
52
|
+
actual_without_id = actual.dup
|
53
|
+
service_id = actual_without_id.delete('id')
|
54
|
+
|
55
|
+
if expected != actual_without_id
|
56
|
+
updated = @driver.update_service(key, expected.merge('id' => service_id), actual) || updated
|
57
|
+
end
|
58
|
+
|
59
|
+
updated
|
60
|
+
end
|
61
|
+
|
62
|
+
def load_file(file)
|
63
|
+
if file.kind_of?(String)
|
64
|
+
open(file) do |f|
|
65
|
+
Lbrt::Service::DSL.parse(f.read, file)
|
66
|
+
end
|
67
|
+
elsif [File, Tempfile].any? {|i| file.kind_of?(i) }
|
68
|
+
Lbrt::Service::DSL.parse(file.read, file.path)
|
69
|
+
else
|
70
|
+
raise TypeError, "can't convert #{file} into File"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Lbrt::Service::DSL::Context
|
2
|
+
include Lbrt::Utils::ContextHelper
|
3
|
+
|
4
|
+
def self.eval(dsl, path, options = {})
|
5
|
+
self.new(path, options) {
|
6
|
+
eval(dsl, binding, path)
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :result
|
11
|
+
|
12
|
+
def initialize(path, options = {}, &block)
|
13
|
+
@path = path
|
14
|
+
@options = options
|
15
|
+
@result = {}
|
16
|
+
instance_eval(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def service(type, title, &block)
|
22
|
+
type = type.to_s
|
23
|
+
title = title.to_s
|
24
|
+
key = [type, title]
|
25
|
+
|
26
|
+
if @result[key]
|
27
|
+
raise "Service `#{type}/#{title}` is already defined"
|
28
|
+
end
|
29
|
+
|
30
|
+
srvc = Lbrt::Service::DSL::Context::Service.new(type, title, &block).result
|
31
|
+
@result[key] = srvc
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Lbrt::Service::DSL::Context::Service
|
2
|
+
REQUIRED_ATTRIBUTES = %w(
|
3
|
+
settings
|
4
|
+
)
|
5
|
+
|
6
|
+
def initialize(type, title, &block)
|
7
|
+
@type = type
|
8
|
+
@title = title
|
9
|
+
@result = {}
|
10
|
+
instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def result
|
14
|
+
REQUIRED_ATTRIBUTES.each do |name|
|
15
|
+
unless @result.has_key?(name)
|
16
|
+
raise "Service `#{@type}/#{@title}`: #{name} is not defined"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
@result
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def settings(value)
|
26
|
+
unless value.is_a?(Hash)
|
27
|
+
raise TypeError, "wrong argument type #{value.class}: #{value.inspect} (expected Hash)"
|
28
|
+
end
|
29
|
+
|
30
|
+
@result['settings'] = value
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Lbrt::Service::DSL::Converter
|
2
|
+
def self.convert(exported, options = {})
|
3
|
+
self.new(exported, options).convert
|
4
|
+
end
|
5
|
+
|
6
|
+
def initialize(exported, options = {})
|
7
|
+
@exported = exported
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert
|
12
|
+
output_services(@exported)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def output_services(service_by_key)
|
18
|
+
services = []
|
19
|
+
|
20
|
+
service_by_key.sort_by(&:first).map do |key, attrs|
|
21
|
+
next unless key.any? {|i| Lbrt::Utils.matched?(i, @options[:target]) }
|
22
|
+
services << output_service(key, attrs)
|
23
|
+
end
|
24
|
+
|
25
|
+
services.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def output_service(key, attrs)
|
29
|
+
type, title = key
|
30
|
+
settings = attrs.fetch('settings')
|
31
|
+
|
32
|
+
<<-EOS
|
33
|
+
service #{type.inspect}, #{title.inspect} do
|
34
|
+
settings #{Lbrt::Utils.unbrace(settings.inspect)}
|
35
|
+
end
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Lbrt::Service::Exporter
|
2
|
+
class << self
|
3
|
+
def export(client, options = {})
|
4
|
+
self.new(client, options).export
|
5
|
+
end
|
6
|
+
end # of class methods
|
7
|
+
|
8
|
+
def initialize(client, options = {})
|
9
|
+
@client = client
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def export
|
14
|
+
services = @client.services.get
|
15
|
+
normalize(services)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def normalize(services)
|
21
|
+
service_by_key = {}
|
22
|
+
|
23
|
+
services.each do |srvc|
|
24
|
+
type = srvc.delete('type')
|
25
|
+
title = srvc.delete('title')
|
26
|
+
service_key = [type, title]
|
27
|
+
|
28
|
+
if service_by_key[service_key]
|
29
|
+
raise "Duplicate service type/title exists: #{type}/#{title}"
|
30
|
+
end
|
31
|
+
|
32
|
+
service_by_key[service_key] = srvc
|
33
|
+
end
|
34
|
+
|
35
|
+
service_by_key
|
36
|
+
end
|
37
|
+
end
|
data/lib/lbrt/space.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
class Lbrt::Space
|
2
|
+
include Lbrt::Logger::Helper
|
3
|
+
|
4
|
+
def initialize(client, options = {})
|
5
|
+
@client = client
|
6
|
+
@options = options
|
7
|
+
@driver = Lbrt::Driver.new(@client, @options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def export(export_options = {})
|
11
|
+
exported = Lbrt::Space::Exporter.export(@client, @options)
|
12
|
+
Lbrt::Space::DSL.convert(exported, @options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def apply(file)
|
16
|
+
walk(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def walk(file)
|
22
|
+
expected = load_file(file)
|
23
|
+
actual = Lbrt::Space::Exporter.export(@client, @options)
|
24
|
+
walk_spaces(expected, actual)
|
25
|
+
end
|
26
|
+
|
27
|
+
def walk_spaces(expected, actual)
|
28
|
+
updated = false
|
29
|
+
|
30
|
+
expected.each do |name_or_id, expected_space|
|
31
|
+
actual_space = actual.delete(name_or_id)
|
32
|
+
|
33
|
+
if not actual_space and name_or_id.is_a?(Integer)
|
34
|
+
actual_space = actual.values.find {|i| i['id'] == name_or_id }
|
35
|
+
end
|
36
|
+
|
37
|
+
unless actual_space
|
38
|
+
updated = @driver.create_space(name_or_id, expected_space) || updated
|
39
|
+
actual_space = expected_space.merge('charts' => {})
|
40
|
+
|
41
|
+
# Set dummy id for dry-run
|
42
|
+
actual_space['id'] ||= -1
|
43
|
+
end
|
44
|
+
|
45
|
+
updated = walk_space(name_or_id, expected_space, actual_space) || updated
|
46
|
+
end
|
47
|
+
|
48
|
+
actual.each do |name_or_id, actual_space|
|
49
|
+
updated = @driver.delete_space(name_or_id, actual_space) || updated
|
50
|
+
end
|
51
|
+
|
52
|
+
updated
|
53
|
+
end
|
54
|
+
|
55
|
+
def walk_space(name_or_id, expected, actual)
|
56
|
+
updated = false
|
57
|
+
space_id = actual.fetch('id')
|
58
|
+
expected_charts = expected.fetch('charts')
|
59
|
+
actual_charts = actual.fetch('charts')
|
60
|
+
updated = walk_charts(name_or_id, space_id, expected_charts, actual_charts) || updated
|
61
|
+
updated
|
62
|
+
end
|
63
|
+
|
64
|
+
def walk_charts(space_name_or_id, space_id, expected, actual)
|
65
|
+
updated = false
|
66
|
+
|
67
|
+
expected.each do |name_or_id, expected_chart|
|
68
|
+
actual_chart = actual.delete(name_or_id)
|
69
|
+
|
70
|
+
if not actual_chart and name_or_id.is_a?(Integer)
|
71
|
+
actual_chart = actual.values.find {|i| i['id'] == name_or_id }
|
72
|
+
end
|
73
|
+
|
74
|
+
if actual_chart
|
75
|
+
updated = walk_chart(space_name_or_id, space_id, name_or_id, expected_chart, actual_chart) || updated
|
76
|
+
else
|
77
|
+
updated = @driver.create_chart(space_name_or_id, space_id, name_or_id, expected_chart) || updated
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
actual.each do |name_or_id, actual_chart|
|
82
|
+
updated = @driver.delete_chart(space_name_or_id, space_id, name_or_id, actual_chart) || updated
|
83
|
+
end
|
84
|
+
|
85
|
+
updated
|
86
|
+
end
|
87
|
+
|
88
|
+
def walk_chart(space_name_or_id, space_id, name_or_id, expected, actual)
|
89
|
+
updated = false
|
90
|
+
|
91
|
+
actual_without_id = actual.dup
|
92
|
+
alert_id = actual_without_id.delete('id')
|
93
|
+
|
94
|
+
if differ_chart?(expected, actual_without_id)
|
95
|
+
updated = @driver.update_chart(space_name_or_id, space_id, name_or_id, expected.merge('id' => alert_id), actual) || updated
|
96
|
+
end
|
97
|
+
|
98
|
+
updated
|
99
|
+
end
|
100
|
+
|
101
|
+
def differ_chart?(chart1, chart2)
|
102
|
+
chart1 = normalize_chart(chart1)
|
103
|
+
chart2 = normalize_chart(chart2)
|
104
|
+
chart1 != chart2
|
105
|
+
end
|
106
|
+
|
107
|
+
def normalize_chart(chart)
|
108
|
+
chart = chart.dup
|
109
|
+
chart_streams = chart['streams'].dup
|
110
|
+
chart_streams.each {|i| i.delete('id') }
|
111
|
+
chart['streams'] = chart_streams
|
112
|
+
chart
|
113
|
+
end
|
114
|
+
|
115
|
+
def load_file(file)
|
116
|
+
if file.kind_of?(String)
|
117
|
+
open(file) do |f|
|
118
|
+
Lbrt::Space::DSL.parse(f.read, file)
|
119
|
+
end
|
120
|
+
elsif [File, Tempfile].any? {|i| file.kind_of?(i) }
|
121
|
+
Lbrt::Space::DSL.parse(file.read, file.path)
|
122
|
+
else
|
123
|
+
raise TypeError, "can't convert #{file} into File"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Lbrt::Space::DSL::Context
|
2
|
+
include Lbrt::Utils::ContextHelper
|
3
|
+
|
4
|
+
def self.eval(dsl, path, options = {})
|
5
|
+
self.new(path, options) {
|
6
|
+
eval(dsl, binding, path)
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :result
|
11
|
+
|
12
|
+
def initialize(path, options = {}, &block)
|
13
|
+
@path = path
|
14
|
+
@options = options
|
15
|
+
@result = {}
|
16
|
+
instance_eval(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def space(name_or_id, &block)
|
22
|
+
if @result[name_or_id]
|
23
|
+
raise "Space `#{name_or_id}` is already defined"
|
24
|
+
end
|
25
|
+
|
26
|
+
spc = Lbrt::Space::DSL::Context::Space.new(name_or_id, &block).result
|
27
|
+
@result[name_or_id] = spc
|
28
|
+
end
|
29
|
+
end
|