guard-bosh 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|