bosh_common 0.5.4 → 1.5.0.pre.1100
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.
- data/lib/common/common.rb +77 -0
- data/lib/common/deep_copy.rb +7 -0
- data/lib/common/errors.rb +7 -0
- data/lib/common/properties/property_helper.rb +2 -2
- data/lib/common/properties/template_evaluation_context.rb +29 -8
- data/lib/common/retryable.rb +74 -0
- data/lib/common/runs_commands.rb +12 -0
- data/lib/common/ssl.rb +107 -0
- data/lib/common/version.rb +1 -1
- data/lib/common/version_number.rb +53 -0
- metadata +21 -30
- data/Rakefile +0 -50
- data/spec/assets/foo1 +0 -0
- data/spec/assets/foo2 +0 -0
- data/spec/spec_helper.rb +0 -13
- data/spec/unit/common_spec.rb +0 -59
- data/spec/unit/exec_spec.rb +0 -114
- data/spec/unit/properties/property_helper_spec.rb +0 -39
- data/spec/unit/properties/template_evaluation_context_spec.rb +0 -112
- data/spec/unit/thread_pool_spec.rb +0 -69
data/lib/common/common.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# Copyright (c) 2012 VMware, Inc.
|
2
|
+
require 'common/errors'
|
3
|
+
require 'common/retryable'
|
2
4
|
|
3
5
|
module Bosh
|
4
6
|
|
@@ -43,5 +45,80 @@ module Bosh
|
|
43
45
|
end
|
44
46
|
|
45
47
|
module_function :which
|
48
|
+
|
49
|
+
# Retries execution of given block until block returns true
|
50
|
+
#
|
51
|
+
# The block is called with two parameters: the number of tries and the most recent
|
52
|
+
# exception. If the block returns true retrying is stopped.
|
53
|
+
# Examples:
|
54
|
+
# Bosh::Common.retryable do |retries, exception|
|
55
|
+
# puts "try #{retries} failed with exception: #{exception}" if retries > 0
|
56
|
+
# pick_up_soap
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# # Wait for EC2 instance to be terminated
|
60
|
+
# Bosh::Common.retryable(on: AWS::EC2::Errors::RequestLimitExceeded) do |retries, exception|
|
61
|
+
# @ec2.instance['i-a3x5g5'].status == :terminated
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
#
|
65
|
+
# @param [Hash] options
|
66
|
+
# @options opts [Proc] :ensure
|
67
|
+
# Default: `Proc.new {}`
|
68
|
+
# Ensure that a block of code is executed, regardless of whether an exception
|
69
|
+
# was raised. It doesn't matter if the block exits normally, if it retries
|
70
|
+
# to execute block of code, or if it is terminated by an uncaught exception
|
71
|
+
# -- the ensure block will get run.
|
72
|
+
# Example:
|
73
|
+
# f = File.open("testfile")
|
74
|
+
#
|
75
|
+
# ensure_cb = Proc.new do |retries|
|
76
|
+
# puts "total retry attempts: #{retries}"
|
77
|
+
#
|
78
|
+
# f.close
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# Bosh::Common.retryable(ensure: ensure_cb) do
|
82
|
+
# # process file
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @options opts [Regexp] :matching
|
86
|
+
# Default: `/.*/`
|
87
|
+
# Retry based on the exception message
|
88
|
+
# Example:
|
89
|
+
# Bosh::Common.retryable(matching: /IO timeout/) do |retries, exception|
|
90
|
+
# raise "yo, IO timeout!" if retries == 0
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# @options opts [Array<ExceptionClass>] :on
|
94
|
+
# Default: `[]`
|
95
|
+
# The array of exception classes to retry on.
|
96
|
+
# Example:
|
97
|
+
# Bosh::Common.retryable(on: [StandardError, ArgumentError]) do
|
98
|
+
# # do something and retry if StandardError or ArgumentError is raised
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# @options opts [Proc, Fixnum] :sleep
|
102
|
+
# Defaults: `lambda { |tries, _| [2**(tries-1), 10].min }`, 1, 2, 4, 8, 10, 10..10 seconds
|
103
|
+
# If a Fixnum is given, sleep that many seconds between retries.
|
104
|
+
# If a Proc is given, call it with the expectation that a Fixnum is returned
|
105
|
+
# and sleep that many seconds. The Proc will be called with the number of tries
|
106
|
+
# and the raised exception (or nil)
|
107
|
+
# Example:
|
108
|
+
# Bosh::Common.retryable(sleep: lambda { |n,e| logger.info(e.message) if e; 4**n }) { }
|
109
|
+
#
|
110
|
+
# @options opts [Fixnum] :tries
|
111
|
+
# Default: 2
|
112
|
+
# Number of times to try
|
113
|
+
# Example:
|
114
|
+
# Bosh::Common.retryable(tries: 3, on: OpenURI::HTTPError) do
|
115
|
+
# xml = open("http://example.com/test.xml").read
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
def retryable(options = {}, &block)
|
119
|
+
Bosh::Retryable.new(options).retryer(&block)
|
120
|
+
end
|
121
|
+
|
122
|
+
module_function :retryable
|
46
123
|
end
|
47
124
|
end
|
@@ -23,7 +23,7 @@ module Bosh::Common
|
|
23
23
|
end
|
24
24
|
|
25
25
|
dst_ref[keys[-1]] ||= {}
|
26
|
-
dst_ref[keys[-1]] = src_ref
|
26
|
+
dst_ref[keys[-1]] = src_ref.nil? ? default : src_ref
|
27
27
|
end
|
28
28
|
|
29
29
|
# @param [Hash] collection Property collection
|
@@ -40,4 +40,4 @@ module Bosh::Common
|
|
40
40
|
ref
|
41
41
|
end
|
42
42
|
end
|
43
|
-
end
|
43
|
+
end
|
@@ -73,18 +73,14 @@ module Bosh::Common
|
|
73
73
|
# @return [Object] Property value
|
74
74
|
# @raise [Bosh::Common::UnknownProperty]
|
75
75
|
def p(*args)
|
76
|
-
names = args[0]
|
77
|
-
default_given = args.size > 1
|
78
|
-
default = args[1]
|
79
|
-
|
80
|
-
names = Array(names) unless names.kind_of?(Array)
|
76
|
+
names = Array(args[0])
|
81
77
|
|
82
78
|
names.each do |name|
|
83
79
|
result = lookup_property(@raw_properties, name)
|
84
80
|
return result unless result.nil?
|
85
81
|
end
|
86
82
|
|
87
|
-
return
|
83
|
+
return args[1] if args.length == 2
|
88
84
|
raise UnknownProperty.new(names)
|
89
85
|
end
|
90
86
|
|
@@ -94,11 +90,12 @@ module Bosh::Common
|
|
94
90
|
def if_p(*names)
|
95
91
|
values = names.map do |name|
|
96
92
|
value = lookup_property(@raw_properties, name)
|
97
|
-
return if value.nil?
|
93
|
+
return ActiveElseBlock.new(self) if value.nil?
|
98
94
|
value
|
99
95
|
end
|
100
96
|
|
101
97
|
yield *values
|
98
|
+
InactiveElseBlock.new
|
102
99
|
end
|
103
100
|
|
104
101
|
# @return [Object] Object representation where all hashes are unrolled
|
@@ -115,5 +112,29 @@ module Bosh::Common
|
|
115
112
|
object
|
116
113
|
end
|
117
114
|
end
|
115
|
+
|
116
|
+
private
|
117
|
+
class ActiveElseBlock
|
118
|
+
def initialize(template_context)
|
119
|
+
@context = template_context
|
120
|
+
end
|
121
|
+
|
122
|
+
def else
|
123
|
+
yield
|
124
|
+
end
|
125
|
+
|
126
|
+
def else_if_p(*names, &block)
|
127
|
+
@context.if_p(*names, &block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class InactiveElseBlock
|
132
|
+
def else
|
133
|
+
end
|
134
|
+
|
135
|
+
def else_if_p(*names)
|
136
|
+
InactiveElseBlock.new
|
137
|
+
end
|
138
|
+
end
|
118
139
|
end
|
119
|
-
end
|
140
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative 'errors'
|
2
|
+
|
3
|
+
module Bosh
|
4
|
+
class Retryable
|
5
|
+
def initialize(options = {})
|
6
|
+
opts = validate_options(options)
|
7
|
+
|
8
|
+
@ensure_callback = opts[:ensure]
|
9
|
+
@matching = opts[:matching]
|
10
|
+
@on_exception = [opts[:on]].flatten
|
11
|
+
@try_count = 0
|
12
|
+
@retry_exception = nil
|
13
|
+
@retry_limit = opts[:tries]
|
14
|
+
@sleeper = opts[:sleep]
|
15
|
+
end
|
16
|
+
|
17
|
+
# this method will loop until the block returns a true value
|
18
|
+
def retryer(&block)
|
19
|
+
loop do
|
20
|
+
@try_count += 1
|
21
|
+
y = yield @try_count, @retry_exception
|
22
|
+
@retry_exception = nil # no exception was raised in the block
|
23
|
+
return y if y
|
24
|
+
raise Bosh::Common::RetryCountExceeded if @try_count >= @retry_limit
|
25
|
+
wait
|
26
|
+
end
|
27
|
+
rescue *@on_exception => exception
|
28
|
+
raise unless exception.message =~ @matching
|
29
|
+
raise if @try_count >= @retry_limit
|
30
|
+
|
31
|
+
@retry_exception = exception
|
32
|
+
wait
|
33
|
+
retry
|
34
|
+
ensure
|
35
|
+
@ensure_callback.call(@try_count)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def validate_options(options)
|
41
|
+
merged_options = default_options.merge(options)
|
42
|
+
invalid_options = merged_options.keys - default_options.keys
|
43
|
+
raise ArgumentError.new("Invalid options: #{invalid_options.join(", ")}") unless invalid_options.empty?
|
44
|
+
|
45
|
+
merged_options
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_options
|
49
|
+
{
|
50
|
+
tries: 2,
|
51
|
+
sleep: exponential_sleeper,
|
52
|
+
on: [],
|
53
|
+
matching: /.*/,
|
54
|
+
ensure: Proc.new {}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def wait
|
59
|
+
sleep(@sleeper.respond_to?(:call) ? @sleeper.call(@try_count, @retry_exception) : @sleeper)
|
60
|
+
rescue *@on_exception
|
61
|
+
# SignalException could be raised while sleeping, so if you want to catch it,
|
62
|
+
# it need to be passed in the list of exceptions to ignore
|
63
|
+
end
|
64
|
+
|
65
|
+
def exponential_sleeper
|
66
|
+
lambda { |tries, _| [2**(tries-1), 10].min } # 1, 2, 4, 8, 10, 10..10 seconds
|
67
|
+
end
|
68
|
+
|
69
|
+
def sleep(*args, &blk)
|
70
|
+
Kernel.sleep(*args, &blk)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'common/exec'
|
2
|
+
|
3
|
+
# Mixin to make it easy to inject an alternate command runner into a class that runs commands.
|
4
|
+
module Bosh
|
5
|
+
module RunsCommands
|
6
|
+
def sh(command)
|
7
|
+
(@command_runner || Bosh::Exec).sh(command)
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :command_runner
|
11
|
+
end
|
12
|
+
end
|
data/lib/common/ssl.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Bosh
|
4
|
+
module Ssl
|
5
|
+
class Certificate
|
6
|
+
class SubjectsDoNotMatchException < RuntimeError;
|
7
|
+
end
|
8
|
+
class MatchingFileNotFound < RuntimeError;
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :key_path, :certificate_path
|
12
|
+
|
13
|
+
def initialize(key_path, certificate_path, common_name, chain_path = nil)
|
14
|
+
@key_path = key_path
|
15
|
+
@certificate_path = certificate_path
|
16
|
+
@chain_path = chain_path
|
17
|
+
@subject_string = subject_string(common_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def key
|
21
|
+
@key.to_pem
|
22
|
+
end
|
23
|
+
|
24
|
+
def certificate
|
25
|
+
@csr_cert.to_pem
|
26
|
+
end
|
27
|
+
|
28
|
+
def chain
|
29
|
+
@chain.to_pem if @chain
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_or_create
|
33
|
+
@key, @csr_cert = load_or_create_key_and_csr_cert
|
34
|
+
@chain = OpenSSL::X509::Certificate.new(File.read(@chain_path)) if @chain_path
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def load_or_create_key_and_csr_cert
|
42
|
+
if File.exists?(@key_path) && !File.exists?(@certificate_path)
|
43
|
+
raise MatchingFileNotFound, 'The key that matches the given certificate could not be found.'
|
44
|
+
end
|
45
|
+
|
46
|
+
if File.exists?(@certificate_path) && !File.exists?(@key_path)
|
47
|
+
raise MatchingFileNotFound, 'The certificate that matches the given key could not be found.'
|
48
|
+
end
|
49
|
+
|
50
|
+
if File.exists?(@key_path) && File.exists?(@certificate_path)
|
51
|
+
load_key_and_csr_cert
|
52
|
+
else
|
53
|
+
create_key_and_csr_cert
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_key_and_csr_cert
|
58
|
+
key = OpenSSL::PKey::RSA.new(File.read(@key_path))
|
59
|
+
csr_cert = OpenSSL::X509::Certificate.new(File.read(@certificate_path))
|
60
|
+
|
61
|
+
[key, csr_cert]
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_key_and_csr_cert
|
65
|
+
subject = OpenSSL::X509::Name.parse(@subject_string)
|
66
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
67
|
+
csr = new_csr(key, subject)
|
68
|
+
csr_cert = new_csr_certificate(key, csr)
|
69
|
+
|
70
|
+
File.write(@key_path, key.to_pem)
|
71
|
+
File.write(@certificate_path, csr_cert.to_pem)
|
72
|
+
|
73
|
+
[key, csr_cert]
|
74
|
+
end
|
75
|
+
|
76
|
+
def new_csr(key, subject)
|
77
|
+
csr = OpenSSL::X509::Request.new
|
78
|
+
csr.version = 0
|
79
|
+
csr.subject = subject
|
80
|
+
csr.public_key = key.public_key
|
81
|
+
csr.sign key, OpenSSL::Digest::SHA1.new
|
82
|
+
|
83
|
+
csr
|
84
|
+
end
|
85
|
+
|
86
|
+
def new_csr_certificate(key, csr)
|
87
|
+
csr_cert = OpenSSL::X509::Certificate.new
|
88
|
+
csr_cert.serial = 0
|
89
|
+
csr_cert.version = 2
|
90
|
+
csr_cert.not_before = Time.now - 60 * 60 * 24
|
91
|
+
csr_cert.not_after = Time.now + 94608000
|
92
|
+
|
93
|
+
csr_cert.subject = csr.subject
|
94
|
+
csr_cert.public_key = csr.public_key
|
95
|
+
csr_cert.issuer = csr.subject
|
96
|
+
|
97
|
+
csr_cert.sign key, OpenSSL::Digest::SHA1.new
|
98
|
+
|
99
|
+
csr_cert
|
100
|
+
end
|
101
|
+
|
102
|
+
def subject_string(common_name)
|
103
|
+
"/C=US/O=Pivotal/CN=#{common_name}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/common/version.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Bosh::Common
|
2
|
+
class VersionNumber
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
def initialize(version_value)
|
6
|
+
@version = version_value.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def <=>(other)
|
10
|
+
v1 = @version
|
11
|
+
v2 = other.to_s
|
12
|
+
return v1 <=> v2 if [v1, v2].all? { |v| v.to_s.match(/^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$/) }
|
13
|
+
|
14
|
+
vp1 = components
|
15
|
+
vp2 = other.components
|
16
|
+
|
17
|
+
[vp1.size, vp2.size].max.times do |i|
|
18
|
+
result = vp1[i].to_i <=> vp2[i].to_i
|
19
|
+
return result unless result == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
0
|
23
|
+
end
|
24
|
+
|
25
|
+
def major
|
26
|
+
components[0].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def minor
|
30
|
+
components[1].to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def components
|
34
|
+
@version.split('.')
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
@version
|
39
|
+
end
|
40
|
+
|
41
|
+
def final?
|
42
|
+
!@version.end_with?('-dev')
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_minor
|
46
|
+
self.class.new("#{major}.#{minor + 1}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def dev
|
50
|
+
final? ? self.class.new("#{@version}-dev") : self
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh_common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 1.5.0.pre.1100
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- VMware
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-12 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: BOSH common
|
15
|
-
|
14
|
+
description: ! 'BOSH common
|
15
|
+
|
16
|
+
a5984f'
|
17
|
+
email: support@cloudfoundry.com
|
16
18
|
executables: []
|
17
19
|
extensions: []
|
18
20
|
extra_rdoc_files: []
|
19
21
|
files:
|
20
22
|
- lib/common/common.rb
|
23
|
+
- lib/common/deep_copy.rb
|
24
|
+
- lib/common/errors.rb
|
21
25
|
- lib/common/exec.rb
|
22
26
|
- lib/common/exec/error.rb
|
23
27
|
- lib/common/exec/result.rb
|
@@ -25,21 +29,17 @@ files:
|
|
25
29
|
- lib/common/properties/errors.rb
|
26
30
|
- lib/common/properties/property_helper.rb
|
27
31
|
- lib/common/properties/template_evaluation_context.rb
|
32
|
+
- lib/common/retryable.rb
|
33
|
+
- lib/common/runs_commands.rb
|
34
|
+
- lib/common/ssl.rb
|
28
35
|
- lib/common/thread_formatter.rb
|
29
36
|
- lib/common/thread_pool.rb
|
30
37
|
- lib/common/version.rb
|
38
|
+
- lib/common/version_number.rb
|
31
39
|
- README
|
32
|
-
|
33
|
-
|
34
|
-
-
|
35
|
-
- spec/spec_helper.rb
|
36
|
-
- spec/unit/common_spec.rb
|
37
|
-
- spec/unit/exec_spec.rb
|
38
|
-
- spec/unit/properties/property_helper_spec.rb
|
39
|
-
- spec/unit/properties/template_evaluation_context_spec.rb
|
40
|
-
- spec/unit/thread_pool_spec.rb
|
41
|
-
homepage: http://www.vmware.com
|
42
|
-
licenses: []
|
40
|
+
homepage: https://github.com/cloudfoundry/bosh
|
41
|
+
licenses:
|
42
|
+
- Apache 2.0
|
43
43
|
post_install_message:
|
44
44
|
rdoc_options: []
|
45
45
|
require_paths:
|
@@ -49,26 +49,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
49
|
requirements:
|
50
50
|
- - ! '>='
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
52
|
+
version: 1.9.3
|
53
53
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
54
|
none: false
|
55
55
|
requirements:
|
56
|
-
- - ! '
|
56
|
+
- - ! '>'
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version:
|
58
|
+
version: 1.3.1
|
59
59
|
requirements: []
|
60
60
|
rubyforge_project:
|
61
|
-
rubygems_version: 1.8.
|
61
|
+
rubygems_version: 1.8.23
|
62
62
|
signing_key:
|
63
63
|
specification_version: 3
|
64
64
|
summary: BOSH common
|
65
|
-
test_files:
|
66
|
-
- spec/assets/foo1
|
67
|
-
- spec/assets/foo2
|
68
|
-
- spec/spec_helper.rb
|
69
|
-
- spec/unit/common_spec.rb
|
70
|
-
- spec/unit/exec_spec.rb
|
71
|
-
- spec/unit/properties/property_helper_spec.rb
|
72
|
-
- spec/unit/properties/template_evaluation_context_spec.rb
|
73
|
-
- spec/unit/thread_pool_spec.rb
|
74
|
-
has_rdoc:
|
65
|
+
test_files: []
|
data/Rakefile
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
-
|
3
|
-
$:.unshift(File.expand_path("../../rake", __FILE__))
|
4
|
-
|
5
|
-
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
|
6
|
-
|
7
|
-
require "rubygems"
|
8
|
-
require "bundler"
|
9
|
-
Bundler.setup(:default, :test)
|
10
|
-
|
11
|
-
require "rake"
|
12
|
-
begin
|
13
|
-
require "rspec/core/rake_task"
|
14
|
-
rescue LoadError
|
15
|
-
end
|
16
|
-
|
17
|
-
require "bundler_task"
|
18
|
-
require "ci_task"
|
19
|
-
|
20
|
-
gem_helper = Bundler::GemHelper.new(Dir.pwd)
|
21
|
-
|
22
|
-
desc "Build BOSH Common gem into the pkg directory"
|
23
|
-
task "build" do
|
24
|
-
gem_helper.build_gem
|
25
|
-
end
|
26
|
-
|
27
|
-
desc "Build and install BOSH Common into system gems"
|
28
|
-
task "install" do
|
29
|
-
Rake::Task["bundler:install"].invoke
|
30
|
-
gem_helper.install_gem
|
31
|
-
end
|
32
|
-
|
33
|
-
BundlerTask.new
|
34
|
-
|
35
|
-
if defined?(RSpec)
|
36
|
-
namespace :spec do
|
37
|
-
desc "Run Unit Tests"
|
38
|
-
rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
|
39
|
-
t.pattern = "spec/unit/**/*_spec.rb"
|
40
|
-
t.rspec_opts = %w(--format progress --colour)
|
41
|
-
end
|
42
|
-
|
43
|
-
CiTask.new do |task|
|
44
|
-
task.rspec_task = rspec_task
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
desc "Run tests"
|
49
|
-
task :spec => %w(spec:unit)
|
50
|
-
end
|
data/spec/assets/foo1
DELETED
File without changes
|
data/spec/assets/foo2
DELETED
File without changes
|
data/spec/spec_helper.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
-
|
3
|
-
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
4
|
-
|
5
|
-
require "rubygems"
|
6
|
-
require "bundler"
|
7
|
-
Bundler.setup(:default, :test)
|
8
|
-
|
9
|
-
require "rspec"
|
10
|
-
|
11
|
-
def asset(file)
|
12
|
-
File.expand_path(File.join(File.dirname(__FILE__), "assets", file))
|
13
|
-
end
|
data/spec/unit/common_spec.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# Copyright (c) 2012 VMware, Inc.
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
require "common/common"
|
6
|
-
|
7
|
-
describe Bosh::Common do
|
8
|
-
|
9
|
-
describe "#symbolize_keys" do
|
10
|
-
ORIGINAL = {
|
11
|
-
"foo1" => "bar",
|
12
|
-
:foo2 => "bar",
|
13
|
-
"foo3" => {
|
14
|
-
"foo4" => "bar"
|
15
|
-
}
|
16
|
-
}.freeze
|
17
|
-
|
18
|
-
EXPECTED = {
|
19
|
-
:foo1 => "bar",
|
20
|
-
:foo2 => "bar",
|
21
|
-
:foo3 => {
|
22
|
-
:foo4 => "bar"
|
23
|
-
}
|
24
|
-
}.freeze
|
25
|
-
|
26
|
-
it "should not modify the original hash" do
|
27
|
-
duplicate = ORIGINAL.dup
|
28
|
-
Bosh::Common.symbolize_keys(ORIGINAL)
|
29
|
-
ORIGINAL.should == duplicate
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should return a new hash with all keys as symbols" do
|
33
|
-
Bosh::Common.symbolize_keys(ORIGINAL).should == EXPECTED
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe "#which" do
|
38
|
-
let(:path) {
|
39
|
-
path = ENV["PATH"]
|
40
|
-
path += ":#{File.expand_path('../../assets', __FILE__)}"
|
41
|
-
}
|
42
|
-
|
43
|
-
it "should return the path when it finds the executable" do
|
44
|
-
Bosh::Common.which("foo1", path).should_not be_nil
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should return the path when it finds an executable" do
|
48
|
-
Bosh::Common.which(%w[foo2 foo1], path).should match(%r{/foo1$})
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should return nil when it isn't executable" do
|
52
|
-
Bosh::Common.which("foo2", path).should be_nil
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should return nil when it doesn't find an executable" do
|
56
|
-
Bosh::Common.which("foo1").should be_nil
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/spec/unit/exec_spec.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
# Copyright (c) 2012 VMware, Inc.
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
require "common/exec"
|
5
|
-
|
6
|
-
describe Bosh::Exec do
|
7
|
-
let(:opts) { {} }
|
8
|
-
|
9
|
-
context "existing command" do
|
10
|
-
|
11
|
-
context "executes successfully" do
|
12
|
-
it "should not fail" do
|
13
|
-
Bosh::Exec.sh("ls /", opts).failed?.should be_false
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should execute block" do
|
17
|
-
block = false
|
18
|
-
Bosh::Exec.sh("ls /", opts) do
|
19
|
-
block = true
|
20
|
-
end
|
21
|
-
block.should be_true
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
context "fails to execute" do
|
26
|
-
it "should raise error by default" do
|
27
|
-
expect {
|
28
|
-
Bosh::Exec.sh("ls /asdasd 2>&1", opts)
|
29
|
-
}.to raise_error { |error|
|
30
|
-
error.should be_a Bosh::Exec::Error
|
31
|
-
error.output.should match /No such file or directory/
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should yield block on false" do
|
36
|
-
opts[:yield] = :on_false
|
37
|
-
block = false
|
38
|
-
Bosh::Exec.sh("ls /asdasd 2>&1", opts) do
|
39
|
-
block = true
|
40
|
-
end
|
41
|
-
block.should be_true
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should return result" do
|
45
|
-
opts[:on_error] = :return
|
46
|
-
Bosh::Exec.sh("ls /asdasd 2>&1", opts).failed?.should be_true
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
context "missing command" do
|
53
|
-
it "should raise error by default" do
|
54
|
-
expect {
|
55
|
-
Bosh::Exec.sh("/asdasd 2>&1", opts)
|
56
|
-
}.to raise_error Bosh::Exec::Error
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should not raise error when requested" do
|
60
|
-
opts[:on_error] = :return
|
61
|
-
expect {
|
62
|
-
Bosh::Exec.sh("/asdasd 2>&1", opts)
|
63
|
-
}.to_not raise_error Bosh::Exec::Error
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should execute block when requested" do
|
67
|
-
opts[:yield] = :on_false
|
68
|
-
expect {
|
69
|
-
Bosh::Exec.sh("/asdasd 2>&1", opts) do
|
70
|
-
raise "foo"
|
71
|
-
end
|
72
|
-
}.to raise_error "foo"
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
context "mock" do
|
78
|
-
it "should be possible fake result" do
|
79
|
-
cmd = "ls /"
|
80
|
-
result = Bosh::Exec::Result.new(cmd, "output", 0)
|
81
|
-
Bosh::Exec.should_receive(:sh).with(cmd).and_return(result)
|
82
|
-
result = Bosh::Exec.sh(cmd)
|
83
|
-
result.success?.should be_true
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
context "module" do
|
88
|
-
it "should be possible to invoke as a module" do
|
89
|
-
Bosh::Exec.sh("ls /").success?.should be_true
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context "include" do
|
94
|
-
class IncludeTest
|
95
|
-
include Bosh::Exec
|
96
|
-
def run
|
97
|
-
sh("ls /")
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.run
|
101
|
-
sh("ls /")
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
it "should add instance method" do
|
106
|
-
inc = IncludeTest.new
|
107
|
-
inc.run.success?.should be_true
|
108
|
-
end
|
109
|
-
|
110
|
-
it "should add class method" do
|
111
|
-
IncludeTest.run.success?.should be_true
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# Copyright (c) 2012 VMware, Inc.
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
require "common/properties"
|
5
|
-
|
6
|
-
describe Bosh::Common::PropertyHelper do
|
7
|
-
|
8
|
-
before(:each) do
|
9
|
-
@helper = Object.new
|
10
|
-
@helper.extend(Bosh::Common::PropertyHelper)
|
11
|
-
end
|
12
|
-
|
13
|
-
it "can copy named property from one collection to another" do
|
14
|
-
dst = {}
|
15
|
-
src = {"foo" => {"bar" => "baz", "secret" => "zazzle"}}
|
16
|
-
|
17
|
-
@helper.copy_property(dst, src, "foo.bar")
|
18
|
-
dst.should == {"foo" => {"bar" => "baz"}}
|
19
|
-
|
20
|
-
@helper.copy_property(dst, src, "no.such.prop", "default")
|
21
|
-
dst.should == {
|
22
|
-
"foo" => {"bar" => "baz"},
|
23
|
-
"no" => {
|
24
|
-
"such" => {"prop" => "default"}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
it "can lookup the property in a Hash using dot-syntax" do
|
30
|
-
properties = {
|
31
|
-
"foo" => {"bar" => "baz"},
|
32
|
-
"router" => {"token" => "foo"}
|
33
|
-
}
|
34
|
-
|
35
|
-
@helper.lookup_property(properties, "foo.bar").should == "baz"
|
36
|
-
@helper.lookup_property(properties, "router").should == {"token" => "foo"}
|
37
|
-
@helper.lookup_property(properties, "no.prop").should be_nil
|
38
|
-
end
|
39
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
# Copyright (c) 2012 VMware, Inc.
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
require "common/properties"
|
5
|
-
|
6
|
-
describe Bosh::Common::TemplateEvaluationContext do
|
7
|
-
|
8
|
-
def eval_template(erb, context)
|
9
|
-
ERB.new(erb).result(context.get_binding)
|
10
|
-
end
|
11
|
-
|
12
|
-
def make(spec)
|
13
|
-
Bosh::Common::TemplateEvaluationContext.new(spec)
|
14
|
-
end
|
15
|
-
|
16
|
-
before(:each) do
|
17
|
-
@spec = {
|
18
|
-
"job" => {
|
19
|
-
"name" => "foobar"
|
20
|
-
},
|
21
|
-
"properties" => {
|
22
|
-
"foo" => "bar",
|
23
|
-
"router" => {"token" => "zbb"},
|
24
|
-
"vtrue" => true,
|
25
|
-
"vfalse" => false
|
26
|
-
},
|
27
|
-
"index" => 0,
|
28
|
-
}
|
29
|
-
|
30
|
-
@context = make(@spec)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "unrolls properties into OpenStruct" do
|
34
|
-
eval_template("<%= properties.foo %>", @context).should == "bar"
|
35
|
-
end
|
36
|
-
|
37
|
-
it "retains raw_properties" do
|
38
|
-
eval_template("<%= raw_properties['router']['token'] %>", @context).
|
39
|
-
should == "zbb"
|
40
|
-
end
|
41
|
-
|
42
|
-
it "supports looking up template index" do
|
43
|
-
eval_template("<%= spec.index %>", @context).should == "0"
|
44
|
-
end
|
45
|
-
|
46
|
-
it "supports 'p' helper" do
|
47
|
-
eval_template("<%= p('router.token') %>", @context).should == "zbb"
|
48
|
-
|
49
|
-
eval_template("<%= p('vtrue') %>", @context).should == "true"
|
50
|
-
eval_template("<%= p('vfalse') %>", @context).should == "false"
|
51
|
-
|
52
|
-
expect {
|
53
|
-
eval_template("<%= p('bar.baz') %>", @context)
|
54
|
-
}.to raise_error(Bosh::Common::UnknownProperty,
|
55
|
-
"Can't find property `[\"bar.baz\"]'")
|
56
|
-
eval_template("<%= p('bar.baz', 22) %>", @context).should == "22"
|
57
|
-
end
|
58
|
-
|
59
|
-
it "supports chaining property lookup via 'p' helper" do
|
60
|
-
eval_template(<<-TMPL, @context).strip.should == "zbb"
|
61
|
-
<%= p(%w(a b router.token c)) %>
|
62
|
-
TMPL
|
63
|
-
|
64
|
-
expect {
|
65
|
-
eval_template(<<-TMPL, @context)
|
66
|
-
<%= p(%w(a b c)) %>
|
67
|
-
TMPL
|
68
|
-
}.to raise_error(Bosh::Common::UnknownProperty,
|
69
|
-
"Can't find property `[\"a\", \"b\", \"c\"]'")
|
70
|
-
|
71
|
-
eval_template(<<-TMPL, @context).strip.should == "22"
|
72
|
-
<%= p(%w(a b c), 22) %>
|
73
|
-
TMPL
|
74
|
-
end
|
75
|
-
|
76
|
-
it "allows 'false' and 'nil' defaults for 'p' helper" do
|
77
|
-
eval_template(<<-TMPL, @context).strip.should == "false"
|
78
|
-
<%= p(%w(a b c), false) %>
|
79
|
-
TMPL
|
80
|
-
|
81
|
-
eval_template(<<-TMPL, @context).strip.should == ""
|
82
|
-
<%= p(%w(a b c), nil) %>
|
83
|
-
TMPL
|
84
|
-
end
|
85
|
-
|
86
|
-
it "supports 'if_p' helper" do
|
87
|
-
template = <<-TMPL
|
88
|
-
<% if_p("router.token") do |token| %>
|
89
|
-
<%= token %>
|
90
|
-
<% end %>
|
91
|
-
TMPL
|
92
|
-
|
93
|
-
eval_template(template, @context).strip.should == "zbb"
|
94
|
-
|
95
|
-
template = <<-TMPL
|
96
|
-
<% if_p("router.token", "foo") do |token, foo| %>
|
97
|
-
<%= token %>, <%= foo %>
|
98
|
-
<% end %>
|
99
|
-
TMPL
|
100
|
-
|
101
|
-
eval_template(template, @context).strip.should == "zbb, bar"
|
102
|
-
|
103
|
-
template = <<-TMPL
|
104
|
-
<% if_p("router.token", "no.such.prop") do |token, none| %>
|
105
|
-
test output
|
106
|
-
<% end %>
|
107
|
-
TMPL
|
108
|
-
|
109
|
-
eval_template(template, @context).strip.should == ""
|
110
|
-
end
|
111
|
-
|
112
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
-
|
3
|
-
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
-
|
5
|
-
require "common/thread_pool"
|
6
|
-
|
7
|
-
describe Bosh::ThreadPool do
|
8
|
-
|
9
|
-
before(:all) do
|
10
|
-
@logger = Logger.new(STDOUT)
|
11
|
-
@logger.level = Logger::INFO
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should respect max threads" do
|
15
|
-
max = 0
|
16
|
-
current = 0
|
17
|
-
lock = Mutex.new
|
18
|
-
|
19
|
-
Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
|
20
|
-
4.times do
|
21
|
-
pool.process do
|
22
|
-
lock.synchronize do
|
23
|
-
current += 1
|
24
|
-
max = current if current > max
|
25
|
-
end
|
26
|
-
sleep(0.050)
|
27
|
-
lock.synchronize do
|
28
|
-
max = current if current > max
|
29
|
-
current -= 1
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
max.should be <= 2
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should raise exceptions" do
|
38
|
-
lambda {
|
39
|
-
Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
|
40
|
-
5.times do |index|
|
41
|
-
pool.process do
|
42
|
-
sleep(0.050)
|
43
|
-
raise "bad" if index == 4
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
}.should raise_exception("bad")
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should stop processing new work when there was an exception" do
|
51
|
-
max = 0
|
52
|
-
lock = Mutex.new
|
53
|
-
|
54
|
-
lambda {
|
55
|
-
Bosh::ThreadPool.new(:max_threads => 1, :logger => @logger).wrap do |pool|
|
56
|
-
10.times do |index|
|
57
|
-
pool.process do
|
58
|
-
lock.synchronize { max = index if index > max }
|
59
|
-
sleep(0.050)
|
60
|
-
raise "bad" if index == 4
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
}.should raise_exception("bad")
|
65
|
-
|
66
|
-
max.should be == 4
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|