bosh-verifyconnections 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 820df08ec6e4f8bb911adf3b77010afeaa429a7f
4
+ data.tar.gz: fa25cf1b90e232c949752801ff3c48f61763acc3
5
+ SHA512:
6
+ metadata.gz: 7a3bdfe381d651ef8df6a21234cde13ea895dcc7c1b425db01e82d6915d0a559a73dbd583d8106ecf45624ee427e348ec7fcfb2575f97105ce2195a62a5106f7
7
+ data.tar.gz: c7e8be56bdf4e734b52651d41a388953d692b0925d9f1b32a669db97e4e33a7fe031049df27b97e30387acdcc4eeb68812b8af56118736971ec26089ce42c120
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/ChangeLog.md ADDED
@@ -0,0 +1,5 @@
1
+ # Change Log
2
+
3
+ ## v1.0
4
+
5
+ * Released May 3rd 2014
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bosh-verifyconnections.gemspec
4
+ gemspec
5
+
6
+ gem "guard-rspec"
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/bosh/verifyconnections/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dr Nic Williams
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # bosh verify connections
2
+
3
+ BOSH CLI plugin that performs job interconnection verifications upon the target deployment
4
+
5
+ 1. Show jobs with static IPs that aren't referenced elsewhere in the deployment properties
6
+ 2. Show IPs in the deployment properties that aren't specified as static IPs by jobs
7
+ 3. What internal DNS hostnames are specified but don't map to a job
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```
15
+ gem 'bosh-verifyconnections'
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```
21
+ bosh verify connections
22
+ ```
23
+
24
+ To see demonstration deployment manifests:
25
+
26
+ ```
27
+ bosh deployment without verification spec/fixtures/job_with_static_ips_but_not_referenced.yml && bosh verify connections
28
+ ```
29
+
30
+ ![v1](https://www.evernote.com/shard/s3/sh/41947f58-90fc-4f62-b0d8-ad3fae84c0a9/5bede6c17dacef652a8758037c223642/deep/0/drnic@drnic----gems-bosh-verifyconnections---zsh---204-48.png)
31
+
32
+ From this example, perhaps `service.host` should be changed to `10.244.0.6`.
33
+
34
+ Others to try:
35
+
36
+ ```
37
+ bosh deployment without verification spec/fixtures/property_is_bosh_dns_but_not_for_bosh_job.yml && bosh verify connections
38
+ bosh deployment without verification spec/fixtures/property_is_static_ip_but_not_assigned_to_job.yml && bosh verify connections
39
+ ```
40
+
41
+ ### Example
42
+
43
+ You can see that deploying Cloud Foundry on bosh-lite includes two static IPs that aren't referenced properties:
44
+
45
+ ```
46
+ $ bosh verify connections
47
+
48
+ Current deployment is /Users/drnic/Projects/ruby/gems/cloudfoundry/bosh-lite/manifests/cf-manifest.yml
49
+
50
+ Job static IPs that are not being referenced by any properties:
51
+ +----------------------------------+--------------------------------+
52
+ | static ip | job/index |
53
+ +----------------------------------+--------------------------------+
54
+ | 10.244.0.34 | ha_proxy_z1/0 |
55
+ | 10.244.0.26 | runner_z1/0 |
56
+ +----------------------------------+--------------------------------+
57
+ ```
58
+
59
+ The `ha_proxy_z1/0` static IP is used for the public access via `10.244.0.34.xip.io`, but theoretically the `runner_z1/0` job has no reason for a static IP.
60
+
61
+ From the [history of cf-release](https://github.com/cloudfoundry/cf-release/commit/858d1b7e1f0544fb9fd4d9a7a1608e542da6bcdd), the static IP was assigned to ease integration testing.
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it ( https://github.com/cloudfoundry-community/bosh-verifyconnections/fork )
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bosh/verifyconnections/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bosh-verifyconnections"
8
+ spec.version = Bosh::VerifyConnections::VERSION
9
+ spec.authors = ["Dr Nic Williams"]
10
+ spec.email = ["drnicwilliams@gmail.com"]
11
+ spec.summary = %q{Performs job interconnection verifications upon the target BOSH deployment manifest file.}
12
+ spec.description = %q{Performs job interconnection verifications upon the target BOSH deployment manifest file.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "bosh_cli", "~> 1.2200.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 2.14"
26
+ spec.add_development_dependency "rspec-fire"
27
+ end
@@ -0,0 +1,41 @@
1
+ module Bosh::Cli::Command
2
+ class SetDeploymentWithoutVerification < Base
3
+ include Bosh::Cli::Validation
4
+
5
+ usage "deployment without verification"
6
+ desc "Ignore the director_uuid being incorrect and set the new deployment anyway"
7
+ def set_current_without_verification(filename = nil)
8
+ if filename.nil?
9
+ show_current
10
+ return
11
+ end
12
+
13
+ manifest_filename = find_deployment(filename)
14
+
15
+ unless File.exists?(manifest_filename)
16
+ err("Missing manifest for `#{filename}'")
17
+ end
18
+
19
+ manifest = load_yaml_file(manifest_filename)
20
+
21
+ unless manifest.is_a?(Hash)
22
+ err("Invalid manifest format")
23
+ end
24
+
25
+ manifest["director_uuid"] = director.uuid
26
+
27
+ tmp_manifest_filename = File.join("/tmp/", "#{manifest["name"]}.yml")
28
+ File.open(tmp_manifest_filename, "w") do |f|
29
+ f.puts(manifest.to_yaml)
30
+ end
31
+
32
+ # change director_uuid
33
+ # store manifest to tmp file
34
+ # set_deployment
35
+
36
+ say("Deployment set to `#{tmp_manifest_filename.make_yellow}'")
37
+ config.set_deployment(tmp_manifest_filename)
38
+ config.save
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,66 @@
1
+ require "core-ext/hash_to_dotted_notation"
2
+
3
+ module Bosh::Cli::Command
4
+ # Performs job interconnection verifications upon the target deployment
5
+ # 1. Show jobs with static IPs that aren't referenced elsewhere in the deployment properties
6
+ # 2. Show IPs in the deployment properties that aren't specified as static IPs by jobs
7
+ # 3. What .*bosh hostnames are specified but don't map to a job
8
+ # 4. Hostnames that don't resolve to any IP
9
+ class VerifyConnections < Base
10
+ include Bosh::Cli::Validation
11
+ include BoshExtensions
12
+
13
+ usage "verify connections"
14
+ desc "Performs job interconnection verifications upon the target deployment"
15
+ def verify_connections
16
+ require "bosh/verifyconnections"
17
+
18
+ show_deployment
19
+ director_model = Bosh::VerifyConnections::Director.new(director.get_status)
20
+ deployment_model = Bosh::VerifyConnections::Deployment.new(deployment, director_model.domain_name)
21
+
22
+ errors = false
23
+ warnings = false
24
+
25
+ items = deployment_model.unreferenced_static_ips_with_job_index
26
+ if items.size > 0
27
+ warnings = true
28
+ nl
29
+ say "Job static IPs that are not being referenced by any properties:".make_yellow
30
+ view = table(items) do |t|
31
+ t.headings = ["static ip", "job/index"]
32
+ items.each { |item| t << item }
33
+ end
34
+ say(view)
35
+ end
36
+
37
+ items = deployment_model.property_static_ips_not_assigned_to_job
38
+ if items.size > 0
39
+ errors = true
40
+ nl
41
+ say "Properties referencing static IPs that do not belong to any job:".make_red
42
+ view = table(items) do |t|
43
+ t.headings = ["property", "static ip", "job name"]
44
+ items.each { |item| t << item }
45
+ end
46
+ say(view)
47
+ end
48
+
49
+ items = deployment_model.property_hostnames_not_mapping_to_job
50
+ if items.size > 0
51
+ errors = true
52
+ nl
53
+ say "Internal hostnames not mapping to any job:".make_red
54
+ view = table(items) do |t|
55
+ t.headings = ["property", "hostname", "job name"]
56
+ items.each { |item| t << item }
57
+ end
58
+ say(view)
59
+ end
60
+
61
+ nl
62
+ err("Please review errors above") if errors
63
+ warning("Please review warnings above") if warnings
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,122 @@
1
+ require "common/deep_copy"
2
+ require "core-ext/hash_deep_merge"
3
+ require "core-ext/hash_to_dotted_notation"
4
+
5
+ module Bosh::VerifyConnections
6
+ class Deployment
7
+ include BoshExtensions
8
+
9
+ attr_reader :deployment, :jobs, :domain_name
10
+
11
+ def initialize(deployment_file, domain_name)
12
+ parse_deployment_file(deployment_file)
13
+ @domain_name = domain_name
14
+ end
15
+
16
+ def deployment_name
17
+ @deployment["name"]
18
+ end
19
+
20
+ def hostnames_offered
21
+ jobs.inject([]) do |dns, job|
22
+ dns.push(*job.hostnames_offered(deployment_name, domain_name))
23
+ dns
24
+ end
25
+ end
26
+
27
+ def static_ips_assigned
28
+ jobs.inject([]) do |ips, job|
29
+ ips.push(*job.static_ips_assigned)
30
+ ips
31
+ end
32
+ end
33
+
34
+ def static_ips_with_job_index
35
+ jobs.inject([]) do |ips, job|
36
+ job.static_ips_assigned.each_with_index do |ip, index|
37
+ job_index = "#{job.job_name}/#{index}"
38
+ ips << [ip, job_index]
39
+ end
40
+ ips
41
+ end
42
+ end
43
+
44
+ # @return Array [ip, job_index]
45
+ def unreferenced_static_ips_with_job_index
46
+ static_ips_with_job_index.reject do |ip, _|
47
+ all_property_values.include?(ip)
48
+ end
49
+ end
50
+
51
+ def all_properties_by_job
52
+ @all_properties_by_job ||= begin
53
+ all = { "global" => global_properties }
54
+ jobs.each do |job|
55
+ all[job.job_name] = job.job_properties
56
+ end
57
+ all
58
+ end
59
+ end
60
+
61
+ def all_property_values
62
+ @all_property_values ||=
63
+ all_properties_by_job.values.map(&:to_dotted_hash).map(&:values).flatten
64
+ end
65
+
66
+ # @return Array [ip, job_name, property_name]
67
+ def property_static_ips_not_assigned_to_job
68
+ result = []
69
+ all_properties_by_job.each do |job_name, properties|
70
+ properties.to_dotted_hash.each do |key, value|
71
+ result << [key, value, job_name] if invalid_static_ip?(value)
72
+ end
73
+ end
74
+ result
75
+ end
76
+
77
+ # @return Array [hostname, job_name, property_name]
78
+ def property_hostnames_not_mapping_to_job
79
+ result = []
80
+ all_properties_by_job.each do |job_name, properties|
81
+ properties.to_dotted_hash.each do |key, value|
82
+ result << [key, value, job_name] if invalid_internal_hostname?(value)
83
+ end
84
+ end
85
+ result
86
+ end
87
+
88
+ def job(job_name)
89
+ jobs.find { |job| job.job_name == job_name }
90
+ end
91
+
92
+ def global_properties
93
+ @deployment["properties"]
94
+ end
95
+
96
+ private
97
+ def parse_deployment_file(deployment_file)
98
+ @deployment_file = deployment_file
99
+ @deployment = load_yaml_file(@deployment_file)
100
+ @jobs = @deployment["jobs"].map do |manifest_job|
101
+ DeploymentJob.new(manifest_job)
102
+ end
103
+ end
104
+
105
+ def invalid_static_ip?(value)
106
+ return false unless value.is_a? String
107
+ parts = value.split(".")
108
+ return false if parts.size != 4
109
+ parts.each do |part|
110
+ return false if part.to_i.to_s != part
111
+ end
112
+ return !static_ips_assigned.include?(value)
113
+ end
114
+
115
+ def invalid_internal_hostname?(value)
116
+ return false unless value.is_a? String
117
+ return false unless (value =~ /\.#{domain_name}$/)
118
+ return !hostnames_offered.include?(value)
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,64 @@
1
+ class Bosh::VerifyConnections::DeploymentJob
2
+ class DnsInvalidCanonicalName < StandardError; end
3
+
4
+ def initialize(job_from_manifest)
5
+ @from_manifest = job_from_manifest
6
+ end
7
+
8
+ def job_name
9
+ @from_manifest["name"]
10
+ end
11
+
12
+ def instances
13
+ @from_manifest["instances"]
14
+ end
15
+
16
+ def networks
17
+ @from_manifest["networks"]
18
+ end
19
+
20
+ def static_ips_assigned
21
+ networks.inject([]) do |ips, network|
22
+ if network["static_ips"]
23
+ ips.push(*network["static_ips"])
24
+ end
25
+ ips
26
+ end
27
+ end
28
+
29
+ def hostnames_offered(deployment_name, dns_suffix)
30
+ deployment_name = dns_canonical(deployment_name)
31
+ dns_suffix = dns_canonical(dns_suffix)
32
+ job_name = dns_canonical(self.job_name)
33
+ networks.inject([]) do |hostnames, network|
34
+ network_name = dns_canonical(network["name"])
35
+ 0.upto(instances-1) do |n|
36
+ hostnames << [n, job_name, network_name, deployment_name, dns_suffix].join(".")
37
+ end
38
+ hostnames
39
+ end
40
+ end
41
+
42
+ def job_properties
43
+ @from_manifest["properties"] || {}
44
+ end
45
+
46
+ private
47
+ def dns_canonical(string)
48
+ unless string
49
+ raise DnsInvalidCanonicalName, "Must provide a string"
50
+ end
51
+ # a-z, 0-9, -, case insensitive, and must start with a letter
52
+ string = string.downcase.gsub(/_/, "-").gsub(/[^a-z0-9-]/, "")
53
+ if string =~ /^(\d|-)/
54
+ raise DnsInvalidCanonicalName,
55
+ "Invalid DNS canonical name `#{string}', must begin with a letter"
56
+ end
57
+ if string =~ /-$/
58
+ raise DnsInvalidCanonicalName,
59
+ "Invalid DNS canonical name `#{string}', can't end with a hyphen"
60
+ end
61
+ string
62
+ end
63
+
64
+ end
@@ -0,0 +1,15 @@
1
+ module Bosh::VerifyConnections
2
+ class Director
3
+ def initialize(status)
4
+ @status = status
5
+ end
6
+
7
+ def dns?
8
+ @status["features"]["dns"] && @status["features"]["dns"]["status"]
9
+ end
10
+
11
+ def domain_name
12
+ @status["features"]["dns"]["extras"]["domain_name"]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ require "bosh/verifyconnections/models/deployment_job"
2
+ require "bosh/verifyconnections/models/deployment"
3
+ require "bosh/verifyconnections/models/director"
@@ -0,0 +1,5 @@
1
+ module Bosh
2
+ module VerifyConnections
3
+ VERSION = "1.0.1"
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Bosh
2
+ module VerifyConnections
3
+ # Your code goes here...
4
+ end
5
+ end
6
+
7
+ require "bosh/verifyconnections/models"
@@ -0,0 +1,34 @@
1
+ # https://github.com/Offirmo/hash-deep-merge/blob/master/lib/hash_deep_merge.rb
2
+ class Hash
3
+
4
+ def deep_merge!(specialized_hash)
5
+ return internal_deep_merge!(self, specialized_hash)
6
+ end
7
+
8
+
9
+ def deep_merge(specialized_hash)
10
+ return internal_deep_merge!(Hash.new.replace(self), specialized_hash)
11
+ end
12
+
13
+ protected
14
+
15
+ # better, recursive, preserving method
16
+ # OK OK this is not the most efficient algorithm,
17
+ # but at last it's *perfectly clear and understandable*
18
+ # so fork and improve if you need 5% more speed, ok ?
19
+ def internal_deep_merge!(source_hash, specialized_hash)
20
+ specialized_hash.each_pair do |rkey, rval|
21
+ if source_hash.has_key?(rkey) then
22
+ if rval.is_a?(Hash) and source_hash[rkey].is_a?(Hash) then
23
+ internal_deep_merge!(source_hash[rkey], rval)
24
+ elsif rval == source_hash[rkey] then
25
+ else
26
+ source_hash[rkey] = rval
27
+ end
28
+ else
29
+ source_hash[rkey] = rval
30
+ end
31
+ end
32
+ source_hash
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ # From http://raycoding.net/2013/08/26/nested-hash-to-dotted-notation-hash-in-ruby/
2
+ class Hash
3
+ def to_dotted_hash(recursive_key = "")
4
+ self.each_with_object({}) do |(k, v), ret|
5
+ key = recursive_key + k.to_s
6
+ if v.is_a? Hash
7
+ ret.merge!(v.to_dotted_hash(key + "."))
8
+ else
9
+ ret[key] = v
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: job_with_static_ips_but_not_referenced
3
+ releases:
4
+ - name: cf
5
+ version: latest
6
+
7
+ networks:
8
+ - name: cf1
9
+ subnets:
10
+ # static
11
+ - cloud_properties:
12
+ name: random
13
+ range: 10.244.0.0/30
14
+ reserved:
15
+ - 10.244.0.1
16
+ static:
17
+ - 10.244.0.2
18
+ - cloud_properties:
19
+ name: random
20
+ range: 10.244.0.4/30
21
+ reserved:
22
+ - 10.244.0.5
23
+ static:
24
+ - 10.244.0.6
25
+ - cloud_properties:
26
+ name: random
27
+ range: 10.244.0.8/30
28
+ reserved:
29
+ - 10.244.0.9
30
+ static:
31
+ - 10.244.0.10
32
+
33
+ # dynamic
34
+ - cloud_properties:
35
+ name: random
36
+ range: 10.244.0.128/30
37
+ reserved:
38
+ - 10.244.0.129
39
+ static: []
40
+ - cloud_properties:
41
+ name: random
42
+ range: 10.244.0.132/30
43
+ reserved:
44
+ - 10.244.0.133
45
+ static: []
46
+ - cloud_properties:
47
+ name: random
48
+ range: 10.244.0.136/30
49
+ reserved:
50
+ - 10.244.0.137
51
+
52
+ jobs:
53
+ - name: ephemeral
54
+ instances: 2
55
+ templates:
56
+ - name: cloud_controller_ng
57
+ networks:
58
+ - name: cf1
59
+ - name: service
60
+ instances: 1
61
+ templates:
62
+ - name: postgres
63
+ networks:
64
+ - name: cf1
65
+ default: [dns, gateway]
66
+ - name: floating
67
+ static_ips:
68
+ - 10.244.0.6
69
+ properties:
70
+ service:
71
+ port: 4444
72
+ extra: property
73
+
74
+ properties:
75
+ service:
76
+ host: 10.244.0.10
77
+ port: 3333
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: job_with_static_ips_but_not_referenced
3
+ releases:
4
+ - name: cf
5
+ version: latest
6
+
7
+ networks:
8
+ - name: cf1
9
+ subnets:
10
+ # static
11
+ - cloud_properties:
12
+ name: random
13
+ range: 10.244.0.0/30
14
+ reserved:
15
+ - 10.244.0.1
16
+ static:
17
+ - 10.244.0.2
18
+ - cloud_properties:
19
+ name: random
20
+ range: 10.244.0.4/30
21
+ reserved:
22
+ - 10.244.0.5
23
+ static:
24
+ - 10.244.0.6
25
+ - cloud_properties:
26
+ name: random
27
+ range: 10.244.0.8/30
28
+ reserved:
29
+ - 10.244.0.9
30
+ static:
31
+ - 10.244.0.10
32
+
33
+ # dynamic
34
+ - cloud_properties:
35
+ name: random
36
+ range: 10.244.0.128/30
37
+ reserved:
38
+ - 10.244.0.129
39
+ static: []
40
+ - cloud_properties:
41
+ name: random
42
+ range: 10.244.0.132/30
43
+ reserved:
44
+ - 10.244.0.133
45
+ static: []
46
+ - cloud_properties:
47
+ name: random
48
+ range: 10.244.0.136/30
49
+ reserved:
50
+ - 10.244.0.137
51
+
52
+ jobs:
53
+ - name: ephemeral
54
+ instances: 2
55
+ templates:
56
+ - name: cloud_controller_ng
57
+ networks:
58
+ - name: cf1
59
+ - name: service
60
+ instances: 1
61
+ templates:
62
+ - name: postgres
63
+ networks:
64
+ - name: cf1
65
+ default: [dns, gateway]
66
+ - name: floating
67
+ static_ips:
68
+ - 10.244.0.6
69
+ properties:
70
+ service:
71
+ port: 4444
72
+ host: 0.service.floating.job-with-static-ips-but-not-referenced.microbosh
73
+ extra: property
74
+
75
+ properties:
76
+ service:
77
+ host: 0.some-service.cf1.job-with-static-ips-but-not-referenced.microbosh
78
+ port: 3333
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: job_with_static_ips_but_not_referenced
3
+ releases:
4
+ - name: cf
5
+ version: latest
6
+
7
+ networks:
8
+ - name: cf1
9
+ subnets:
10
+ # static
11
+ - cloud_properties:
12
+ name: random
13
+ range: 10.244.0.0/30
14
+ reserved:
15
+ - 10.244.0.1
16
+ static:
17
+ - 10.244.0.2
18
+ - cloud_properties:
19
+ name: random
20
+ range: 10.244.0.4/30
21
+ reserved:
22
+ - 10.244.0.5
23
+ static:
24
+ - 10.244.0.6
25
+ - cloud_properties:
26
+ name: random
27
+ range: 10.244.0.8/30
28
+ reserved:
29
+ - 10.244.0.9
30
+ static:
31
+ - 10.244.0.10
32
+
33
+ # dynamic
34
+ - cloud_properties:
35
+ name: random
36
+ range: 10.244.0.128/30
37
+ reserved:
38
+ - 10.244.0.129
39
+ static: []
40
+ - cloud_properties:
41
+ name: random
42
+ range: 10.244.0.132/30
43
+ reserved:
44
+ - 10.244.0.133
45
+ static: []
46
+ - cloud_properties:
47
+ name: random
48
+ range: 10.244.0.136/30
49
+ reserved:
50
+ - 10.244.0.137
51
+
52
+ jobs:
53
+ - name: ephemeral
54
+ instances: 2
55
+ templates:
56
+ - name: cloud_controller_ng
57
+ networks:
58
+ - name: cf1
59
+ properties:
60
+ service:
61
+ host: 10.244.0.6
62
+ - name: service
63
+ instances: 1
64
+ templates:
65
+ - name: postgres
66
+ networks:
67
+ - name: cf1
68
+ default: [dns, gateway]
69
+ - name: floating
70
+ static_ips:
71
+ - 10.244.0.6
72
+
73
+ properties:
74
+ service:
75
+ host: 10.244.0.10
76
+ port: 3333
@@ -0,0 +1,37 @@
1
+ describe Bosh::VerifyConnections::DeploymentJob do
2
+ context "static_ips" do
3
+ subject do
4
+ Bosh::VerifyConnections::DeploymentJob.new({
5
+ "name" => "service_name",
6
+ "instances" => 1,
7
+ "templates" => [{
8
+ "name" => "postgres"
9
+ }],
10
+ "networks" => [
11
+ {
12
+ "name" => "internal_network",
13
+ "default" => ["dns", "gateway"]
14
+ },
15
+ {
16
+ "name" => "floating",
17
+ "static_ips" => ["10.244.0.6"]
18
+ }
19
+ ],
20
+ "properties" => {
21
+ "port" => 3333,
22
+ "nested" => {
23
+ "key" => "value"
24
+ }
25
+ }
26
+ })
27
+ end
28
+ it { expect(subject.instances).to eq(1) }
29
+ it { expect(subject.static_ips_assigned).to eq(["10.244.0.6"])}
30
+ it { expect(subject.hostnames_offered("my_deployment", "suffix")).to eq([
31
+ "0.service-name.internal-network.my-deployment.suffix",
32
+ "0.service-name.floating.my-deployment.suffix"
33
+ ])}
34
+ it { expect(subject.job_properties).to eq({"port" => 3333, "nested" => {"key" => "value"}}) }
35
+
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ describe Bosh::VerifyConnections::Deployment do
2
+ context "job_with_static_ips_but_not_referenced" do
3
+ let(:manifest) { spec_fixture("job_with_static_ips_but_not_referenced.yml") }
4
+ subject { Bosh::VerifyConnections::Deployment.new(manifest, "microbosh") }
5
+
6
+ it { expect(subject.jobs.size).to eq(2) }
7
+ it { expect(subject.hostnames_offered).to eq([
8
+ "0.ephemeral.cf1.job-with-static-ips-but-not-referenced.microbosh",
9
+ "1.ephemeral.cf1.job-with-static-ips-but-not-referenced.microbosh",
10
+ "0.service.cf1.job-with-static-ips-but-not-referenced.microbosh",
11
+ "0.service.floating.job-with-static-ips-but-not-referenced.microbosh"
12
+ ])}
13
+
14
+ it { expect(subject.static_ips_assigned).to eq(["10.244.0.6"])}
15
+ it { expect(subject.global_properties).to eq({
16
+ "service" => {
17
+ "host" => "10.244.0.10",
18
+ "port" => 3333
19
+ }
20
+ })}
21
+
22
+ it { expect(subject.unreferenced_static_ips_with_job_index).to eq([["10.244.0.6", "service/0"]]) }
23
+ it { expect(subject.property_static_ips_not_assigned_to_job).to eq([["service.host", "10.244.0.10", "global"]]) }
24
+ it { expect(subject.property_hostnames_not_mapping_to_job).to eq([]) }
25
+ end
26
+
27
+ context "property_is_bosh_dns_but_not_for_bosh_job" do
28
+ let(:manifest) { spec_fixture("property_is_bosh_dns_but_not_for_bosh_job.yml") }
29
+ subject { Bosh::VerifyConnections::Deployment.new(manifest, "microbosh") }
30
+
31
+ it { expect(subject.unreferenced_static_ips_with_job_index).to eq([["10.244.0.6", "service/0"]]) }
32
+ it { expect(subject.property_static_ips_not_assigned_to_job).to eq([]) }
33
+ it { expect(subject.property_hostnames_not_mapping_to_job).to eq([
34
+ ["service.host", "0.some-service.cf1.job-with-static-ips-but-not-referenced.microbosh", "global"]
35
+ ]) }
36
+ end
37
+
38
+ context "property_is_static_ip_but_not_assigned_to_job" do
39
+ let(:manifest) { spec_fixture("property_is_static_ip_but_not_assigned_to_job.yml") }
40
+ subject { Bosh::VerifyConnections::Deployment.new(manifest, "microbosh") }
41
+
42
+ it { expect(subject.unreferenced_static_ips_with_job_index).to eq([]) }
43
+ it { expect(subject.property_static_ips_not_assigned_to_job).to eq([["service.host", "10.244.0.10", "global"]]) }
44
+ it { expect(subject.property_hostnames_not_mapping_to_job).to eq([]) }
45
+ end
46
+
47
+
48
+ end
@@ -0,0 +1,59 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup(:default, :test)
8
+
9
+ $:.unshift(File.expand_path("../../lib", __FILE__))
10
+
11
+ require "rspec/core"
12
+ require 'rspec/fire'
13
+
14
+ # for the #sh helper
15
+ require "rake"
16
+ require "rake/file_utils"
17
+
18
+ # bosh_cli
19
+ require "cli"
20
+
21
+ require "bosh/verifyconnections"
22
+
23
+ RSpec.configure do |config|
24
+ config.include(RSpec::Fire)
25
+ end
26
+
27
+ # load all files in spec/support/* (but not lower down)
28
+ Dir[File.dirname(__FILE__) + '/support/*'].each do |path|
29
+ require path unless File.directory?(path)
30
+ end
31
+
32
+ def spec_fixture(filename)
33
+ File.expand_path("../fixtures/#{filename}", __FILE__)
34
+ end
35
+
36
+ def setup_home_dir
37
+ home_dir = File.expand_path("../../tmp/home", __FILE__)
38
+ FileUtils.rm_rf(home_dir)
39
+ FileUtils.mkdir_p(home_dir)
40
+ ENV['HOME'] = home_dir
41
+ end
42
+
43
+ # returns the file path to a file
44
+ # in the fake $HOME folder
45
+ def home_file(*path)
46
+ File.join(ENV['HOME'], *path)
47
+ end
48
+
49
+ def in_home_dir(&block)
50
+ FileUtils.chdir(home_file, &block)
51
+ end
52
+
53
+ def get_tmp_file_path(content)
54
+ tmp_file = File.open(File.join(Dir.mktmpdir, "tmp"), "w")
55
+ tmp_file.write(content)
56
+ tmp_file.close
57
+
58
+ tmp_file.path
59
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bosh-verifyconnections
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dr Nic Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bosh_cli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2200.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2200.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-fire
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Performs job interconnection verifications upon the target BOSH deployment
84
+ manifest file.
85
+ email:
86
+ - drnicwilliams@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - ChangeLog.md
94
+ - Gemfile
95
+ - Guardfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - bosh-verifyconnections.gemspec
100
+ - lib/bosh/cli/commands/set_deployment_without_verification.rb
101
+ - lib/bosh/cli/commands/verifyconnections.rb
102
+ - lib/bosh/verifyconnections.rb
103
+ - lib/bosh/verifyconnections/models.rb
104
+ - lib/bosh/verifyconnections/models/deployment.rb
105
+ - lib/bosh/verifyconnections/models/deployment_job.rb
106
+ - lib/bosh/verifyconnections/models/director.rb
107
+ - lib/bosh/verifyconnections/version.rb
108
+ - lib/core-ext/hash_deep_merge.rb
109
+ - lib/core-ext/hash_to_dotted_notation.rb
110
+ - spec/fixtures/combination_of_correct_dns_and_static_ip_connections.yml
111
+ - spec/fixtures/job_with_static_ips_but_not_referenced.yml
112
+ - spec/fixtures/property_is_bosh_dns_but_not_for_bosh_job.yml
113
+ - spec/fixtures/property_is_static_ip_but_not_assigned_to_job.yml
114
+ - spec/models/deployment_job_spec.rb
115
+ - spec/models/deployment_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: ''
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.2.2
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Performs job interconnection verifications upon the target BOSH deployment
141
+ manifest file.
142
+ test_files:
143
+ - spec/fixtures/combination_of_correct_dns_and_static_ip_connections.yml
144
+ - spec/fixtures/job_with_static_ips_but_not_referenced.yml
145
+ - spec/fixtures/property_is_bosh_dns_but_not_for_bosh_job.yml
146
+ - spec/fixtures/property_is_static_ip_but_not_assigned_to_job.yml
147
+ - spec/models/deployment_job_spec.rb
148
+ - spec/models/deployment_spec.rb
149
+ - spec/spec_helper.rb