bosh-verifyconnections 1.0.1

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