guard-bosh 0.2.0 → 0.3.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 +4 -4
- data/lib/guard/bosh.rb +4 -0
- data/lib/guard/bosh/apply_specification.rb +13 -43
- data/lib/guard/bosh/change_assessor.rb +11 -5
- data/lib/guard/bosh/effective_properties_calculator.rb +4 -0
- data/lib/guard/bosh/global_properties_loader.rb +2 -0
- data/lib/guard/bosh/job_default_properties_loader.rb +1 -0
- data/lib/guard/bosh/job_properties_loader.rb +1 -0
- data/lib/guard/bosh/job_repository.rb +2 -0
- data/lib/guard/bosh/network_generator.rb +57 -0
- data/lib/guard/bosh/notifier.rb +13 -2
- data/lib/guard/bosh/package_resolver.rb +3 -0
- data/lib/guard/bosh/template_checker.rb +28 -9
- data/lib/guard/bosh/template_renderer.rb +41 -13
- data/lib/guard/bosh/templates/Guardfile +1 -1
- data/spec/guard/bosh/apply_specification_spec.rb +22 -59
- data/spec/guard/bosh/change_assessor_spec.rb +10 -8
- data/spec/guard/bosh/effective_properties_calculator_spec.rb +14 -13
- data/spec/guard/bosh/job_default_properties_loader_spec.rb +6 -3
- data/spec/guard/bosh/job_properties_loader_spec.rb +13 -3
- data/spec/guard/bosh/job_repository_spec.rb +8 -6
- data/spec/guard/bosh/network_generator_spec.rb +65 -0
- data/spec/guard/bosh/notifier_spec.rb +27 -3
- data/spec/guard/bosh/template_checker_spec.rb +4 -2
- data/spec/guard/bosh/template_renderer_spec.rb +57 -8
- data/spec/guard/bosh_spec.rb +15 -12
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55e6d1e34e436b7f4669fada4b65d4681947b44b
|
4
|
+
data.tar.gz: 6249a5b3b822a446e533fd0afc2cd4861f62ce70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f9f84431e819e25dcfa8676b6c47a4e8b728795539f1337b60f01c2372572bc8b3383bc99c972aea5b469d004d09c59d0813c99a4e977fd1a31e2b8b632d26b
|
7
|
+
data.tar.gz: 40deae949545a9a4fda3327835509d2c921808a1826e47e48a5adc7e1545f03572711d0e5238ba1b869232399747a483189e5e2a498197fea981fa9fa29da939
|
data/lib/guard/bosh.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'guard/compat/plugin'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
2
4
|
|
3
5
|
module Guard
|
6
|
+
# Guard BOSH Plugin
|
4
7
|
class Bosh < Plugin
|
5
8
|
require 'pathname'
|
6
9
|
|
@@ -40,6 +43,7 @@ module Guard
|
|
40
43
|
notify_errors(errors)
|
41
44
|
end
|
42
45
|
|
46
|
+
# rubocop:disable Metrics/MethodLength
|
43
47
|
def run_on_modifications(paths)
|
44
48
|
change_scope, job_name = @change_assessor.determine_scope(paths)
|
45
49
|
errors = case change_scope
|
@@ -1,13 +1,15 @@
|
|
1
|
-
require 'ipaddr'
|
2
|
-
|
3
1
|
module Guard
|
4
2
|
class Bosh
|
3
|
+
# Simulated BOSH Apply Spec.
|
5
4
|
class ApplySpecification
|
6
|
-
def initialize(
|
5
|
+
def initialize(
|
6
|
+
deployment_manifest:, package_resolver:, network_generator:)
|
7
7
|
@manifest = deployment_manifest
|
8
8
|
@package_resolver = package_resolver
|
9
|
+
@network_generator = network_generator
|
9
10
|
end
|
10
11
|
|
12
|
+
# rubocop:disable Metrics/MethodLength
|
11
13
|
def generate(properties:, job_name:)
|
12
14
|
{
|
13
15
|
'deployment' => @manifest['name'],
|
@@ -46,12 +48,12 @@ module Guard
|
|
46
48
|
all_packages.inject({}) do |result, package|
|
47
49
|
result.merge(
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
package => {
|
52
|
+
'name' => package,
|
53
|
+
'version' => '1.0',
|
54
|
+
'sha1' => 'b945ce51b3635bb0ebfb2207323514381bcee824',
|
55
|
+
'blobstore_id' => '608c41bc-d491-4773-9812-8f24276eace1'
|
56
|
+
}
|
55
57
|
|
56
58
|
)
|
57
59
|
end
|
@@ -79,40 +81,8 @@ module Guard
|
|
79
81
|
end
|
80
82
|
|
81
83
|
def network(job_name)
|
82
|
-
|
83
|
-
|
84
|
-
network_definition = @manifest['networks'].find do |n|
|
85
|
-
n['name'] == job_network['name']
|
86
|
-
end
|
87
|
-
{
|
88
|
-
job_network['name'] => {
|
89
|
-
'cloud_properties' => network_definition['subnets'].first['cloud_properties'],
|
90
|
-
'dns_record_name' => dns_record_name(
|
91
|
-
job_name, job_network['name'], @manifest['name']),
|
92
|
-
'ip' => ip_address(job_network, network_definition),
|
93
|
-
'netmask' => netmask(network_definition['subnets'].first['range']),
|
94
|
-
'default' => %w(dns gateway)
|
95
|
-
}
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
def ip_address(job_network, network_definition)
|
100
|
-
if job_network.key?('static_ips') &&
|
101
|
-
Array(job_network['static_ips']).any?
|
102
|
-
job_network['static_ips'].first
|
103
|
-
else
|
104
|
-
# We could be better here and calculate the dynamic address properly
|
105
|
-
network_definition['subnets'].first['range'].split('/').first
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def dns_record_name(job, network, deployment)
|
110
|
-
"0.#{job}.#{network}.#{deployment}.bosh".gsub('_', '-')
|
111
|
-
end
|
112
|
-
|
113
|
-
def netmask(range)
|
114
|
-
cidr = range.split('/').last
|
115
|
-
IPAddr.new('255.255.255.255').mask(cidr).to_s
|
84
|
+
@network_generator.generate(
|
85
|
+
deployment_manifest: @manifest, job_name: job_name)
|
116
86
|
end
|
117
87
|
|
118
88
|
def resource_pool(job_name)
|
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
1
3
|
module Guard
|
2
4
|
class Bosh
|
5
|
+
# Determines the impact of a code change to enable a subset of files to be
|
6
|
+
# re-evaluated.
|
3
7
|
class ChangeAssessor
|
4
8
|
def initialize(deployment_manifest)
|
5
9
|
@deployment_manifest = deployment_manifest
|
@@ -9,11 +13,7 @@ module Guard
|
|
9
13
|
paths = raw_paths.map { |p| Pathname.new(p) }
|
10
14
|
return :all if paths.include?(@deployment_manifest)
|
11
15
|
|
12
|
-
|
13
|
-
p.dirname.basename.to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
spec_scope = scope(jobs, :all_templates_for_job)
|
16
|
+
spec_scope = scope(jobs_for_paths(paths), :all_templates_for_job)
|
17
17
|
return spec_scope if spec_scope
|
18
18
|
|
19
19
|
jobs = paths.select { |p| template_path?(p) }.map do |t|
|
@@ -27,6 +27,12 @@ module Guard
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
+
def jobs_for_paths(paths)
|
31
|
+
paths.select { |p| spec_path?(p) }.map do |p|
|
32
|
+
p.dirname.basename.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
30
36
|
def spec_path?(path)
|
31
37
|
path.basename.to_s == 'spec'
|
32
38
|
end
|
@@ -2,6 +2,10 @@ require 'deep_merge'
|
|
2
2
|
|
3
3
|
module Guard
|
4
4
|
class Bosh
|
5
|
+
# The effective set of properties is the union of:
|
6
|
+
# * The default properties declared in the job spec
|
7
|
+
# * The properties declared at the top-level of the manifest
|
8
|
+
# * The properties declared at the job-level of the manifest
|
5
9
|
class EffectivePropertiesCalculator
|
6
10
|
def initialize(loaders:)
|
7
11
|
@loaders = loaders
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
class Bosh
|
5
|
+
# Generates a simulated network section for the apply spec
|
6
|
+
class NetworkGenerator
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
8
|
+
def generate(deployment_manifest:, job_name:)
|
9
|
+
job_network, network_definition =
|
10
|
+
manifest_sections(deployment_manifest, job_name)
|
11
|
+
{
|
12
|
+
job_network['name'] => {
|
13
|
+
'cloud_properties' => network_definition['subnets'].first[
|
14
|
+
'cloud_properties'],
|
15
|
+
'dns_record_name' => dns_record_name(
|
16
|
+
job_name, job_network['name'], deployment_manifest['name']),
|
17
|
+
'ip' => ip_address(job_network, network_definition),
|
18
|
+
'netmask' => netmask(network_definition['subnets'].first['range']),
|
19
|
+
'default' => %w(dns gateway)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def manifest_sections(deployment_manifest, job_name)
|
27
|
+
manifest_job = deployment_manifest['jobs'].find do |job|
|
28
|
+
job['name'] == job_name
|
29
|
+
end
|
30
|
+
job_network = manifest_job['networks'].first
|
31
|
+
network_definition = deployment_manifest['networks'].find do |n|
|
32
|
+
n['name'] == job_network['name']
|
33
|
+
end
|
34
|
+
[job_network, network_definition]
|
35
|
+
end
|
36
|
+
|
37
|
+
def ip_address(job_network, network_definition)
|
38
|
+
if job_network.key?('static_ips') &&
|
39
|
+
Array(job_network['static_ips']).any?
|
40
|
+
job_network['static_ips'].first
|
41
|
+
else
|
42
|
+
# We could be better here and calculate the dynamic address properly
|
43
|
+
network_definition['subnets'].first['range'].split('/').first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def dns_record_name(job, network, deployment)
|
48
|
+
"0.#{job}.#{network}.#{deployment}.bosh".gsub('_', '-')
|
49
|
+
end
|
50
|
+
|
51
|
+
def netmask(range)
|
52
|
+
cidr = range.split('/').last
|
53
|
+
IPAddr.new('255.255.255.255').mask(cidr).to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/guard/bosh/notifier.rb
CHANGED
@@ -2,18 +2,29 @@ require 'guard/compat'
|
|
2
2
|
|
3
3
|
module Guard
|
4
4
|
class Bosh
|
5
|
+
# Report success or failure to the user
|
5
6
|
class Notifier
|
6
7
|
def notify(errors)
|
7
8
|
if errors.empty?
|
8
9
|
Guard::Compat::UI.notify(
|
9
10
|
'Succeeded', title: 'BOSH', image: :success, priority: -2)
|
10
11
|
else
|
11
|
-
Guard::Compat::UI.error(
|
12
|
-
'%s: %s' % [errors.first[:template], errors.first[:detail]])
|
12
|
+
Guard::Compat::UI.error(error_line(errors))
|
13
13
|
Guard::Compat::UI.notify(
|
14
14
|
'Failed', title: 'BOSH', image: :failed, priority: 2)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def error_line(errors)
|
21
|
+
error = errors.first
|
22
|
+
[
|
23
|
+
error[:template],
|
24
|
+
error[:line] == :unknown ? '?' : error[:line],
|
25
|
+
" #{error[:detail]}"
|
26
|
+
].join(':')
|
27
|
+
end
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
@@ -1,5 +1,16 @@
|
|
1
|
+
require 'guard/bosh/apply_specification'
|
2
|
+
require 'guard/bosh/effective_properties_calculator'
|
3
|
+
require 'guard/bosh/global_properties_loader'
|
4
|
+
require 'guard/bosh/job_default_properties_loader'
|
5
|
+
require 'guard/bosh/job_properties_loader'
|
6
|
+
require 'guard/bosh/network_generator'
|
7
|
+
require 'guard/bosh/package_resolver'
|
8
|
+
require 'guard/bosh/template_renderer'
|
9
|
+
|
1
10
|
module Guard
|
2
11
|
class Bosh
|
12
|
+
# Encapsulates building the apply spec, and rendering job templates against
|
13
|
+
# it to identify errors.
|
3
14
|
class TemplateChecker
|
4
15
|
def initialize(deployment_manifest:,
|
5
16
|
properties_calculator:,
|
@@ -22,22 +33,30 @@ module Guard
|
|
22
33
|
end
|
23
34
|
|
24
35
|
def self.build(deployment_manifest:, release_dir:)
|
25
|
-
|
36
|
+
new(
|
37
|
+
deployment_manifest: deployment_manifest,
|
38
|
+
properties_calculator:
|
39
|
+
properties_calculator(deployment_manifest, release_dir),
|
40
|
+
apply_specification:
|
41
|
+
apply_specification(deployment_manifest, release_dir),
|
42
|
+
template_renderer: TemplateRenderer.new
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.properties_calculator(deployment_manifest, release_dir)
|
47
|
+
EffectivePropertiesCalculator.new(loaders: [
|
26
48
|
JobDefaultPropertiesLoader.new(release_dir: release_dir),
|
27
49
|
GlobalPropertiesLoader.new(deployment_manifest: deployment_manifest),
|
28
50
|
JobPropertiesLoader.new(deployment_manifest: deployment_manifest)
|
29
51
|
])
|
30
|
-
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.apply_specification(deployment_manifest, release_dir)
|
55
|
+
ApplySpecification.new(
|
31
56
|
deployment_manifest: deployment_manifest,
|
57
|
+
network_generator: NetworkGenerator.new,
|
32
58
|
package_resolver: PackageResolver.new(release_dir)
|
33
59
|
)
|
34
|
-
template_renderer = TemplateRenderer.new
|
35
|
-
new(
|
36
|
-
deployment_manifest: deployment_manifest,
|
37
|
-
properties_calculator: properties_calculator,
|
38
|
-
apply_specification: apply_specification,
|
39
|
-
template_renderer: template_renderer
|
40
|
-
)
|
41
60
|
end
|
42
61
|
end
|
43
62
|
end
|
@@ -4,37 +4,65 @@ require 'bosh/template/unknown_property'
|
|
4
4
|
|
5
5
|
module Guard
|
6
6
|
class Bosh
|
7
|
+
# Render a template with the provided context and report any errors.
|
7
8
|
class TemplateRenderer
|
8
9
|
def render(context:, template:)
|
9
10
|
renderer = ::Bosh::Template::Renderer.new(
|
10
11
|
context: JSON.generate(context))
|
11
12
|
|
12
|
-
# The re-writing of messages we do here is intended to make the output
|
13
|
-
# more readable, but may not be wise.
|
14
13
|
begin
|
15
14
|
renderer.render(template)
|
16
15
|
{ template: template, status: :success, detail: '' }
|
17
|
-
rescue
|
18
|
-
|
19
|
-
rescue NoMethodError => e
|
20
|
-
error(template, e.message.sub(/ for #<[^>]+>$/, ''))
|
21
|
-
rescue NameError => e
|
22
|
-
error(template, e.message.sub(/ for #<[^>]+>$/, ''))
|
23
|
-
rescue SyntaxError => e
|
24
|
-
error(template, e.message.split("\n").first.sub(
|
25
|
-
/^\(erb\):[0-9]+: /, ''))
|
16
|
+
rescue StandardError, SyntaxError => e
|
17
|
+
generate_user_facing_error(template, e)
|
26
18
|
end
|
27
19
|
end
|
28
20
|
|
29
21
|
private
|
30
22
|
|
31
|
-
def
|
23
|
+
def generate_user_facing_error(template, ex)
|
24
|
+
case ex
|
25
|
+
when ::Bosh::Template::UnknownProperty
|
26
|
+
error(template, "missing property: #{ex.name}", line(ex))
|
27
|
+
when NoMethodError, NameError
|
28
|
+
error(template, remove_bosh_template(ex.message), line(ex))
|
29
|
+
when SyntaxError
|
30
|
+
context = find_erb_error(ex.message)
|
31
|
+
error(template, context['message'], context['line'].to_i)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def error(template, message, line)
|
32
36
|
{
|
33
37
|
template: template,
|
34
38
|
status: :failure,
|
35
|
-
detail: message
|
39
|
+
detail: message,
|
40
|
+
line: line
|
36
41
|
}
|
37
42
|
end
|
43
|
+
|
44
|
+
def line(error)
|
45
|
+
erb_error = find_erb_error(error.backtrace)
|
46
|
+
if erb_error.nil?
|
47
|
+
:unknown
|
48
|
+
else
|
49
|
+
erb_error['line'].to_i
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ERB_LINE_PATTERN = /^\(erb\):(?<line>[0-9]+): ?(?<message>.*)/
|
54
|
+
|
55
|
+
def find_erb_error(error_lines)
|
56
|
+
# '(erb):4: syntax error, unexpected keyword_do_block'
|
57
|
+
Array(error_lines).lazy.grep(ERB_LINE_PATTERN) do |error_line|
|
58
|
+
ERB_LINE_PATTERN.match(error_line)
|
59
|
+
end.first
|
60
|
+
end
|
61
|
+
|
62
|
+
def remove_bosh_template(message)
|
63
|
+
# ' for #<Bosh::Template::EvaluationContext:0x00000000000000>'
|
64
|
+
message.sub(/ for #<Bosh::Template::[^>]+>$/, '')
|
65
|
+
end
|
38
66
|
end
|
39
67
|
end
|
40
68
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'guard/bosh/apply_specification'
|
2
|
+
require 'guard/bosh/network_generator'
|
3
|
+
require 'guard/bosh/package_resolver'
|
2
4
|
|
3
5
|
describe Guard::Bosh::ApplySpecification do
|
4
|
-
let(:package_resolver) {
|
6
|
+
let(:package_resolver) { instance_double(Guard::Bosh::PackageResolver) }
|
7
|
+
let(:network_generator) { instance_double(Guard::Bosh::NetworkGenerator) }
|
5
8
|
subject do
|
6
9
|
Guard::Bosh::ApplySpecification.new(
|
7
10
|
deployment_manifest: manifest_stub,
|
8
|
-
package_resolver: package_resolver
|
11
|
+
package_resolver: package_resolver,
|
12
|
+
network_generator: network_generator
|
9
13
|
)
|
10
14
|
end
|
11
15
|
|
@@ -15,26 +19,14 @@ describe Guard::Bosh::ApplySpecification do
|
|
15
19
|
'jobs' => [{
|
16
20
|
'instances' => 1,
|
17
21
|
'name' => 'redis_leader_z1',
|
18
|
-
'networks' => [{ 'name' => 'redis1', 'static_ips' => ['203.0.113.2'] }],
|
19
22
|
'persistent_disk' => 0,
|
20
23
|
'resource_pool' => 'small_z1',
|
21
24
|
'templates' => [{ 'name' => 'redis', 'release' => 'redis' }]
|
22
25
|
}],
|
23
|
-
'networks' => [
|
24
|
-
{
|
25
|
-
'name' => 'redis1',
|
26
|
-
'subnets' => [{
|
27
|
-
'cloud_properties' => { 'name' => 'iaas_network_name' },
|
28
|
-
'range' => '203.0.113.2/24',
|
29
|
-
'static' => ['10.244.2.2']
|
30
|
-
}]
|
31
|
-
}
|
32
|
-
],
|
33
26
|
'resource_pools' => [
|
34
27
|
{
|
35
28
|
'cloud_properties' => { 'name' => 'random' },
|
36
29
|
'name' => 'small_z1',
|
37
|
-
'network' => 'redis1',
|
38
30
|
'size' => 3,
|
39
31
|
'stemcell' => {
|
40
32
|
'name' => 'bosh-warden-boshlite-ubuntu-trusty-go_agent',
|
@@ -46,7 +38,12 @@ describe Guard::Bosh::ApplySpecification do
|
|
46
38
|
end
|
47
39
|
|
48
40
|
before do
|
49
|
-
allow(package_resolver).to receive(:resolve).with(
|
41
|
+
allow(package_resolver).to receive(:resolve).with(
|
42
|
+
'redis').and_return(['redis'])
|
43
|
+
allow(network_generator).to receive(:generate).with(
|
44
|
+
deployment_manifest: manifest_stub,
|
45
|
+
job_name: 'redis_leader_z1'
|
46
|
+
)
|
50
47
|
end
|
51
48
|
|
52
49
|
it 'includes the effective properties provided' do
|
@@ -94,7 +91,8 @@ describe Guard::Bosh::ApplySpecification do
|
|
94
91
|
'blobstore_id' => '608c41bc-d491-4773-9812-8f24276eace1'
|
95
92
|
}
|
96
93
|
}
|
97
|
-
expect(package_resolver).to receive(:resolve).with(
|
94
|
+
expect(package_resolver).to receive(:resolve).with(
|
95
|
+
'redis').and_return(['redis'])
|
98
96
|
apply_spec = subject.generate(properties: {}, job_name: 'redis_leader_z1')
|
99
97
|
expect(apply_spec['packages']).to eq(expected_packages)
|
100
98
|
end
|
@@ -104,49 +102,14 @@ describe Guard::Bosh::ApplySpecification do
|
|
104
102
|
expect(apply_spec['configuration_hash']).to_not be_empty
|
105
103
|
end
|
106
104
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
'default' => %w(dns gateway)
|
116
|
-
}
|
117
|
-
}
|
118
|
-
apply_spec = subject.generate(properties: {}, job_name: 'redis_leader_z1')
|
119
|
-
expect(apply_spec['networks']).to eq(expected_networks)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'when the job has a dynamic ip' do
|
124
|
-
let(:manifest_stub_without_static_ip) do
|
125
|
-
manifest_stub.tap do |stub|
|
126
|
-
stub['jobs'].first['networks'].first.delete('static_ips')
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
subject do
|
131
|
-
Guard::Bosh::ApplySpecification.new(
|
132
|
-
deployment_manifest: manifest_stub_without_static_ip,
|
133
|
-
package_resolver: package_resolver
|
134
|
-
)
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'includes the network config' do
|
138
|
-
expected_networks = {
|
139
|
-
'redis1' => {
|
140
|
-
'cloud_properties' => { 'name' => 'iaas_network_name' },
|
141
|
-
'dns_record_name' => '0.redis-leader-z1.redis1.redis-deployment.bosh',
|
142
|
-
'ip' => '203.0.113.2',
|
143
|
-
'netmask' => '255.255.255.0',
|
144
|
-
'default' => %w(dns gateway)
|
145
|
-
}
|
146
|
-
}
|
147
|
-
apply_spec = subject.generate(properties: {}, job_name: 'redis_leader_z1')
|
148
|
-
expect(apply_spec['networks']).to eq(expected_networks)
|
149
|
-
end
|
105
|
+
it 'includes the network config' do
|
106
|
+
generated_networks = { 'redis1' => {} }
|
107
|
+
expect(network_generator).to receive(:generate).with(
|
108
|
+
deployment_manifest: manifest_stub,
|
109
|
+
job_name: 'redis_leader_z1'
|
110
|
+
).and_return(generated_networks)
|
111
|
+
apply_spec = subject.generate(properties: {}, job_name: 'redis_leader_z1')
|
112
|
+
expect(apply_spec['networks']).to eq(generated_networks)
|
150
113
|
end
|
151
114
|
|
152
115
|
it 'includes the resource pool' do
|
@@ -8,21 +8,21 @@ describe Guard::Bosh::ChangeAssessor do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
context 'when a final.yml has been modified' do
|
11
|
-
it 'reports
|
11
|
+
it 'reports scope that means the change can be ignored' do
|
12
12
|
change_scope, _ = subject.determine_scope(['config/final.yml'])
|
13
13
|
expect(change_scope).to eq(:none)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
context 'when the deployment manifest has been modified' do
|
18
|
-
it 'reports
|
18
|
+
it 'reports scope meaning all jobs and templates must be re-evaluated' do
|
19
19
|
change_scope, _ = subject.determine_scope(['templates/manifest.yml'])
|
20
20
|
expect(change_scope).to eq(:all)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'when a job spec has been modified' do
|
25
|
-
it 'reports
|
25
|
+
it 'reports scope meaning templates must be evaluated for a single job' do
|
26
26
|
change_scope, _ = subject.determine_scope(['jobs/redis/spec'])
|
27
27
|
expect(change_scope).to eq(:all_templates_for_job)
|
28
28
|
end
|
@@ -33,18 +33,20 @@ describe Guard::Bosh::ChangeAssessor do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
context 'when a job template has been modified' do
|
36
|
-
it 'reports
|
37
|
-
change_scope, _ = subject.determine_scope(
|
36
|
+
it 'reports scope meaning a single template must be evaluated for a job' do
|
37
|
+
change_scope, _ = subject.determine_scope(
|
38
|
+
['jobs/redis/templates/config/redis.conf.erb'])
|
38
39
|
expect(change_scope).to eq(:single_template)
|
39
40
|
end
|
40
41
|
it 'reports the correct job name' do
|
41
|
-
_, job_name = subject.determine_scope(
|
42
|
+
_, job_name = subject.determine_scope(
|
43
|
+
['jobs/redis/templates/config/redis.conf.erb'])
|
42
44
|
expect(job_name).to eq('redis')
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
48
|
context 'when multiple job specs have been modified across jobs' do
|
47
|
-
it 'reports
|
49
|
+
it 'reports scope that means all jobs and templates must be re-evaluated' do
|
48
50
|
change_scope, _ = subject.determine_scope([
|
49
51
|
'jobs/redis/spec',
|
50
52
|
'jobs/postgresql/spec'
|
@@ -54,7 +56,7 @@ describe Guard::Bosh::ChangeAssessor do
|
|
54
56
|
end
|
55
57
|
|
56
58
|
context 'when multiple templates have been modified across jobs' do
|
57
|
-
it 'reports
|
59
|
+
it 'reports scope that means all jobs and templates must be re-evaluated' do
|
58
60
|
change_scope, _ = subject.determine_scope([
|
59
61
|
'jobs/redis/templates/config/redis.conf.erb',
|
60
62
|
'jobs/postgresql/templates/config/pg_hba.conf.erb'
|
@@ -27,30 +27,31 @@ describe Guard::Bosh::EffectivePropertiesCalculator do
|
|
27
27
|
it 'merges the properties' do
|
28
28
|
expect(job_defaults_loader).to receive(:load_properties).and_return(
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
'redis' => {
|
31
|
+
'password' => 'password',
|
32
|
+
'port' => 6379
|
33
|
+
}
|
34
34
|
|
35
35
|
)
|
36
36
|
expect(global_properties_loader).to receive(:load_properties).and_return(
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
'redis' => {
|
39
|
+
'password' => 'secure-password',
|
40
|
+
'slaves' => ['203.0.113.3', '203.0.113.4']
|
41
|
+
},
|
42
|
+
'network' => 'redis1'
|
43
43
|
|
44
44
|
)
|
45
45
|
expect(job_properties_loader).to receive(:load_properties).and_return(
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
'redis' => {
|
48
|
+
'master' => '203.0.113.2'
|
49
|
+
}
|
50
50
|
|
51
51
|
)
|
52
52
|
|
53
|
-
properties = subject.calculate_effective_properties(
|
53
|
+
properties = subject.calculate_effective_properties(
|
54
|
+
manifest_job_name: 'redis_z1')
|
54
55
|
expect(properties).to eq(
|
55
56
|
'redis' => {
|
56
57
|
'password' => 'secure-password',
|
@@ -38,7 +38,8 @@ describe Guard::Bosh::JobDefaultPropertiesLoader do
|
|
38
38
|
|
39
39
|
it 'returns the properties that have defaults in the job spec' do
|
40
40
|
expect(YAML).to receive(:load_file).with(
|
41
|
-
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
41
|
+
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
42
|
+
job_spec_excerpt)
|
42
43
|
job_defaults = subject.load_properties(job_name: 'job-name')
|
43
44
|
expect(job_defaults).to include(
|
44
45
|
'redis' => {
|
@@ -54,14 +55,16 @@ describe Guard::Bosh::JobDefaultPropertiesLoader do
|
|
54
55
|
|
55
56
|
it 'ignores properties that do not have defaults defined' do
|
56
57
|
expect(YAML).to receive(:load_file).with(
|
57
|
-
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
58
|
+
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
59
|
+
job_spec_excerpt)
|
58
60
|
job_defaults = subject.load_properties(job_name: 'job-name')
|
59
61
|
expect(job_defaults['redis'].keys).not_to include('master')
|
60
62
|
end
|
61
63
|
|
62
64
|
it 'includes an empty hash for intermediate keys' do
|
63
65
|
expect(YAML).to receive(:load_file).with(
|
64
|
-
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
66
|
+
Pathname.new('/path/to/a/release/jobs/job-name/spec')).and_return(
|
67
|
+
job_spec_excerpt)
|
65
68
|
job_defaults = subject.load_properties(job_name: 'job-name')
|
66
69
|
expect(job_defaults['redis'].keys).to include('blazingly')
|
67
70
|
expect(job_defaults['redis']['blazingly']).to be_empty
|
@@ -7,7 +7,9 @@ describe Guard::Bosh::JobPropertiesLoader do
|
|
7
7
|
{
|
8
8
|
'instances' => 1,
|
9
9
|
'name' => 'redis_leader_z1',
|
10
|
-
'networks' => [
|
10
|
+
'networks' => [
|
11
|
+
{ 'name' => 'redis1', 'static_ips' => ['10.244.2.6'] }
|
12
|
+
],
|
11
13
|
'persistent_disk' => 0,
|
12
14
|
'properties' => { 'network' => 'redis1', 'redis' => nil },
|
13
15
|
'resource_pool' => 'small_z1',
|
@@ -16,9 +18,17 @@ describe Guard::Bosh::JobPropertiesLoader do
|
|
16
18
|
{
|
17
19
|
'instances' => 2,
|
18
20
|
'name' => 'redis_z1',
|
19
|
-
'networks' => [
|
21
|
+
'networks' => [
|
22
|
+
{
|
23
|
+
'name' => 'redis1',
|
24
|
+
'static_ips' => ['10.244.2.10', '10.244.2.14']
|
25
|
+
}
|
26
|
+
],
|
20
27
|
'persistent_disk' => 0,
|
21
|
-
'properties' => {
|
28
|
+
'properties' => {
|
29
|
+
'network' => 'redis1',
|
30
|
+
'redis' => { 'master' => '10.244.2.6' }
|
31
|
+
},
|
22
32
|
'resource_pool' => 'small_z1',
|
23
33
|
'templates' => [{ 'name' => 'redis', 'release' => 'redis' }],
|
24
34
|
'update' => { 'canaries' => 10 }
|
@@ -34,18 +34,20 @@ describe Guard::Bosh::JobRepository do
|
|
34
34
|
describe '#find_by_template' do
|
35
35
|
context 'when there are multiple jobs that use a job template' do
|
36
36
|
it 'returns all jobs that use that template' do
|
37
|
-
expect(subject.find_by_template('redis')).to eq(
|
37
|
+
expect(subject.find_by_template('redis')).to eq(
|
38
|
+
%w(redis_leader_z1 redis_slave_z2))
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
describe '#template_paths' do
|
43
44
|
it 'looks up the template paths from the job specification' do
|
44
|
-
expect(YAML).to receive(:load_file).with(
|
45
|
-
'
|
46
|
-
'
|
47
|
-
|
48
|
-
|
45
|
+
expect(YAML).to receive(:load_file).with(
|
46
|
+
Pathname.new('jobs/redis/spec')).and_return(
|
47
|
+
'templates' => {
|
48
|
+
'redis_ctl.sh.erb' => 'bin/redis_ctl.sh',
|
49
|
+
'redis.conf.erb' => 'config/redis.conf'
|
50
|
+
}
|
49
51
|
)
|
50
52
|
expect(subject.template_paths('redis')).to eq([
|
51
53
|
Pathname.new('jobs/redis/templates/redis_ctl.sh.erb'),
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'guard/bosh/network_generator'
|
2
|
+
|
3
|
+
describe Guard::Bosh::NetworkGenerator do
|
4
|
+
let(:manifest_stub) do
|
5
|
+
{
|
6
|
+
'name' => 'redis-deployment',
|
7
|
+
'jobs' => [{
|
8
|
+
'name' => 'redis_leader_z1',
|
9
|
+
'networks' => [{ 'name' => 'redis1', 'static_ips' => ['203.0.113.2'] }],
|
10
|
+
'templates' => [{ 'name' => 'redis', 'release' => 'redis' }]
|
11
|
+
}],
|
12
|
+
'networks' => [
|
13
|
+
{
|
14
|
+
'name' => 'redis1',
|
15
|
+
'subnets' => [{
|
16
|
+
'cloud_properties' => { 'name' => 'iaas_network_name' },
|
17
|
+
'range' => '203.0.113.2/24',
|
18
|
+
'static' => ['10.244.2.2']
|
19
|
+
}]
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when the job has a static ip' do
|
26
|
+
it 'includes the network config' do
|
27
|
+
expected_networks = {
|
28
|
+
'redis1' => {
|
29
|
+
'cloud_properties' => { 'name' => 'iaas_network_name' },
|
30
|
+
'dns_record_name' => '0.redis-leader-z1.redis1.redis-deployment.bosh',
|
31
|
+
'ip' => '203.0.113.2',
|
32
|
+
'netmask' => '255.255.255.0',
|
33
|
+
'default' => %w(dns gateway)
|
34
|
+
}
|
35
|
+
}
|
36
|
+
generated_networks = subject.generate(
|
37
|
+
deployment_manifest: manifest_stub, job_name: 'redis_leader_z1')
|
38
|
+
expect(generated_networks).to eq(expected_networks)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when the job has a dynamic ip' do
|
43
|
+
let(:manifest_stub_without_static_ip) do
|
44
|
+
manifest_stub.tap do |stub|
|
45
|
+
stub['jobs'].first['networks'].first.delete('static_ips')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'includes the network config' do
|
50
|
+
expected_networks = {
|
51
|
+
'redis1' => {
|
52
|
+
'cloud_properties' => { 'name' => 'iaas_network_name' },
|
53
|
+
'dns_record_name' => '0.redis-leader-z1.redis1.redis-deployment.bosh',
|
54
|
+
'ip' => '203.0.113.2',
|
55
|
+
'netmask' => '255.255.255.0',
|
56
|
+
'default' => %w(dns gateway)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
generated_networks = subject.generate(
|
60
|
+
deployment_manifest: manifest_stub_without_static_ip,
|
61
|
+
job_name: 'redis_leader_z1')
|
62
|
+
expect(generated_networks).to eq(expected_networks)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -27,14 +27,38 @@ describe Guard::Bosh::Notifier do
|
|
27
27
|
priority: 2
|
28
28
|
)
|
29
29
|
subject.notify([
|
30
|
-
{
|
30
|
+
{
|
31
|
+
template: 'config.erb',
|
32
|
+
status: :failure,
|
33
|
+
detail: 'Missing property: redis.port'
|
34
|
+
}
|
31
35
|
])
|
32
36
|
end
|
33
37
|
it 'outputs the template the error occurred in and the detail' do
|
34
|
-
expect(Guard::Compat::UI).to receive(:error).with(
|
38
|
+
expect(Guard::Compat::UI).to receive(:error).with(
|
39
|
+
'config.erb:10: missing property: redis.port')
|
35
40
|
subject.notify([
|
36
|
-
{
|
41
|
+
{
|
42
|
+
template: 'config.erb',
|
43
|
+
status: :failure,
|
44
|
+
detail: 'missing property: redis.port',
|
45
|
+
line: 10
|
46
|
+
}
|
37
47
|
])
|
38
48
|
end
|
49
|
+
context 'when the line number is not known' do
|
50
|
+
it 'outputs the template the error occurred in and the detail' do
|
51
|
+
expect(Guard::Compat::UI).to receive(:error).with(
|
52
|
+
'config.erb:?: missing property: redis.port')
|
53
|
+
subject.notify([
|
54
|
+
{
|
55
|
+
template: 'config.erb',
|
56
|
+
status: :failure,
|
57
|
+
detail: 'missing property: redis.port',
|
58
|
+
line: :unknown
|
59
|
+
}
|
60
|
+
])
|
61
|
+
end
|
62
|
+
end
|
39
63
|
end
|
40
64
|
end
|
@@ -23,7 +23,8 @@ describe Guard::Bosh::TemplateChecker do
|
|
23
23
|
|
24
24
|
before do
|
25
25
|
allow(properties_calculator).to receive(:calculate_effective_properties)
|
26
|
-
allow(apply_specification).to receive(:generate).and_return(
|
26
|
+
allow(apply_specification).to receive(:generate).and_return(
|
27
|
+
'apply' => 'specification')
|
27
28
|
allow(template_renderer).to receive(:render)
|
28
29
|
end
|
29
30
|
|
@@ -56,7 +57,8 @@ describe Guard::Bosh::TemplateChecker do
|
|
56
57
|
end
|
57
58
|
|
58
59
|
it 'returns any errors generated by the template render' do
|
59
|
-
expect(template_renderer).to receive(:render).and_return(
|
60
|
+
expect(template_renderer).to receive(:render).and_return(
|
61
|
+
['missing property'])
|
60
62
|
errors = subject.check(
|
61
63
|
manifest_job_name: 'redis_leader_z1',
|
62
64
|
job_name: 'redis',
|
@@ -21,15 +21,28 @@ describe Guard::Bosh::TemplateRenderer do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
let(:backtrace) do
|
25
|
+
[
|
26
|
+
"gems/bosh-template-0/lib/bosh/template/evaluation_context.rb:00:in `p'",
|
27
|
+
"(erb):3:in `get_binding'",
|
28
|
+
"rubies/ruby-0.0.0/lib/ruby/0.0.0/erb.rb:000:in `eval'"
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_backtrace(error)
|
33
|
+
error.tap { |e| e.set_backtrace(backtrace) }
|
34
|
+
end
|
35
|
+
|
24
36
|
context 'when the template refers to an unknown property' do
|
25
37
|
it 'reports the missing property' do
|
26
38
|
expect(bosh_renderer).to receive(:render).with('config.erb').and_raise(
|
27
|
-
::Bosh::Template::UnknownProperty.new('redis.port'))
|
39
|
+
with_backtrace(::Bosh::Template::UnknownProperty.new('redis.port')))
|
28
40
|
result = subject.render(context: {}, template: 'config.erb')
|
29
41
|
expect(result).to eq(
|
30
42
|
template: 'config.erb',
|
31
43
|
status: :failure,
|
32
|
-
detail: 'missing property: redis.port'
|
44
|
+
detail: 'missing property: redis.port',
|
45
|
+
line: 3
|
33
46
|
)
|
34
47
|
end
|
35
48
|
end
|
@@ -37,12 +50,19 @@ describe Guard::Bosh::TemplateRenderer do
|
|
37
50
|
context 'when the template calls a misnamed helper method' do
|
38
51
|
it 'reports the missing helper method' do
|
39
52
|
expect(bosh_renderer).to receive(:render).with('config.erb').and_raise(
|
40
|
-
|
53
|
+
with_backtrace(
|
54
|
+
NoMethodError.new(
|
55
|
+
"undefined method `o' for "\
|
56
|
+
'#<Bosh::Template::EvaluationContext:0x00000000000000>'
|
57
|
+
)
|
58
|
+
)
|
59
|
+
)
|
41
60
|
result = subject.render(context: {}, template: 'config.erb')
|
42
61
|
expect(result).to eq(
|
43
62
|
template: 'config.erb',
|
44
63
|
status: :failure,
|
45
|
-
detail: "undefined method `o'"
|
64
|
+
detail: "undefined method `o'",
|
65
|
+
line: 3
|
46
66
|
)
|
47
67
|
end
|
48
68
|
end
|
@@ -50,12 +70,19 @@ describe Guard::Bosh::TemplateRenderer do
|
|
50
70
|
context 'when the template references a missing name' do
|
51
71
|
it 'reports the missing name' do
|
52
72
|
expect(bosh_renderer).to receive(:render).with('config.erb').and_raise(
|
53
|
-
|
73
|
+
with_backtrace(
|
74
|
+
NameError.new(
|
75
|
+
"undefined local variable or method `missing' for "\
|
76
|
+
'#<Bosh::Template::EvaluationContext:0x00000000000000>'
|
77
|
+
)
|
78
|
+
)
|
79
|
+
)
|
54
80
|
result = subject.render(context: {}, template: 'config.erb')
|
55
81
|
expect(result).to eq(
|
56
82
|
template: 'config.erb',
|
57
83
|
status: :failure,
|
58
|
-
detail: "undefined local variable or method `missing'"
|
84
|
+
detail: "undefined local variable or method `missing'",
|
85
|
+
line: 3
|
59
86
|
)
|
60
87
|
end
|
61
88
|
end
|
@@ -63,13 +90,35 @@ describe Guard::Bosh::TemplateRenderer do
|
|
63
90
|
context 'when the template is not well-formed' do
|
64
91
|
it 'reports the template error' do
|
65
92
|
expect(bosh_renderer).to receive(:render).with('config.erb').and_raise(
|
66
|
-
|
93
|
+
with_backtrace(
|
94
|
+
SyntaxError.new(
|
95
|
+
'(erb):7: syntax error, unexpected end-of-input, '\
|
96
|
+
"expecting keyword_end\n; _erbout.force_encoding(__ENCODING__)"
|
97
|
+
)
|
98
|
+
)
|
99
|
+
)
|
67
100
|
result = subject.render(context: {}, template: 'config.erb')
|
68
101
|
expect(result).to eq(
|
69
102
|
template: 'config.erb',
|
70
103
|
status: :failure,
|
71
|
-
detail: 'syntax error, unexpected end-of-input, expecting keyword_end'
|
104
|
+
detail: 'syntax error, unexpected end-of-input, expecting keyword_end',
|
105
|
+
line: 7
|
72
106
|
)
|
73
107
|
end
|
74
108
|
end
|
109
|
+
|
110
|
+
context 'when the backtrace does not include an (erb) line' do
|
111
|
+
it 'reports the template error but without a line number' do
|
112
|
+
error = NameError.new(
|
113
|
+
"undefined local variable or method `missing' for "\
|
114
|
+
'#<Bosh::Template::EvaluationContext:0x00000000000000>')
|
115
|
+
error.set_backtrace([
|
116
|
+
"gems/bosh-template-0/lib/bosh/template/evaluation_context.rb:00:in `p'"
|
117
|
+
])
|
118
|
+
expect(bosh_renderer).to receive(:render).with(
|
119
|
+
'config.erb').and_raise(error)
|
120
|
+
result = subject.render(context: {}, template: 'config.erb')
|
121
|
+
expect(result).to include(line: :unknown)
|
122
|
+
end
|
123
|
+
end
|
75
124
|
end
|
data/spec/guard/bosh_spec.rb
CHANGED
@@ -100,10 +100,11 @@ describe Guard::Bosh do
|
|
100
100
|
expect(job_repository).to receive(:find_by_template).with(
|
101
101
|
'redis').and_return(%w(redis_leader_z1 redis_slave_z2))
|
102
102
|
|
103
|
-
expect(job_repository).to receive(:template_paths).with(
|
104
|
-
'
|
105
|
-
|
106
|
-
|
103
|
+
expect(job_repository).to receive(:template_paths).with(
|
104
|
+
'redis').and_return([
|
105
|
+
'jobs/redis/templates/redis_ctl.sh.erb',
|
106
|
+
'jobs/redis/templates/redis.conf.erb'
|
107
|
+
])
|
107
108
|
end
|
108
109
|
context 'when there are no errors' do
|
109
110
|
it 'checks the template for errors' do
|
@@ -137,20 +138,22 @@ describe Guard::Bosh do
|
|
137
138
|
before do
|
138
139
|
expect(job_repository).to receive(:job_templates).and_return(
|
139
140
|
%w(postgresql redis))
|
140
|
-
expect(job_repository).to receive(:template_paths).with(
|
141
|
-
'
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
'
|
146
|
-
|
141
|
+
expect(job_repository).to receive(:template_paths).with(
|
142
|
+
'postgresql').and_return([
|
143
|
+
'jobs/postgresql/templates/pg_hba.conf.erb'
|
144
|
+
])
|
145
|
+
expect(job_repository).to receive(:template_paths).with(
|
146
|
+
'redis').and_return([
|
147
|
+
'jobs/redis/templates/redis_ctl.sh.erb',
|
148
|
+
'jobs/redis/templates/redis.conf.erb'
|
149
|
+
])
|
147
150
|
expect(template_checker).to receive(:check).with(
|
148
151
|
manifest_job_name: 'redis_slave_z2',
|
149
152
|
job_name: 'redis',
|
150
153
|
template: 'jobs/redis/templates/redis.conf.erb'
|
151
154
|
).and_return([])
|
152
155
|
expect(job_repository).to receive(:find_by_template).with(
|
153
|
-
|
156
|
+
'redis').and_return(%w(redis_leader_z1 redis_slave_z2))
|
154
157
|
expect(job_repository).to receive(:find_by_template).with(
|
155
158
|
'postgresql').and_return(['postgresql_z1'])
|
156
159
|
expect(template_checker).to receive(:check).with(
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guard-bosh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Crump
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bosh-template
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '10.4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.29'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.29'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: simplecov
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +137,7 @@ files:
|
|
123
137
|
- lib/guard/bosh/job_default_properties_loader.rb
|
124
138
|
- lib/guard/bosh/job_properties_loader.rb
|
125
139
|
- lib/guard/bosh/job_repository.rb
|
140
|
+
- lib/guard/bosh/network_generator.rb
|
126
141
|
- lib/guard/bosh/notifier.rb
|
127
142
|
- lib/guard/bosh/package_resolver.rb
|
128
143
|
- lib/guard/bosh/template_checker.rb
|
@@ -135,6 +150,7 @@ files:
|
|
135
150
|
- spec/guard/bosh/job_default_properties_loader_spec.rb
|
136
151
|
- spec/guard/bosh/job_properties_loader_spec.rb
|
137
152
|
- spec/guard/bosh/job_repository_spec.rb
|
153
|
+
- spec/guard/bosh/network_generator_spec.rb
|
138
154
|
- spec/guard/bosh/notifier_spec.rb
|
139
155
|
- spec/guard/bosh/package_resolver_spec.rb
|
140
156
|
- spec/guard/bosh/template_checker_spec.rb
|
@@ -161,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
177
|
version: '0'
|
162
178
|
requirements: []
|
163
179
|
rubyforge_project:
|
164
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.2.2
|
165
181
|
signing_key:
|
166
182
|
specification_version: 4
|
167
183
|
summary: Fast feedback when developing BOSH releases
|