bosh_cpi_networking 2.5

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: 80456c92fa86f1e403aa2c5c9db8da44b91cb51b
4
+ data.tar.gz: 31d96dfaae8ba996c5878e405d0c0445cbc19dfb
5
+ SHA512:
6
+ metadata.gz: 3905e313c73b7ed04f3b1974562b5e0b1200433da41315b2759c8ab1ae8cf6c0cb3d003c3612659da560b28b5563542041e978ac4cb1d95e00aa2fb117c95a2a
7
+ data.tar.gz: a4fa23dece8e65f1f062cd82f92cc5f56dc7932ffd40e3f7638a7ba3289ca9b0ce0c756c56bd5983d375292ff1e6a52865c0f7d0f818e86653fd9b036b2d55db
data/lib/bosh/cpi.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Bosh
2
+ module Cpi; end
3
+ end
4
+
5
+ require 'bosh/cpi/cli'
6
+ require 'bosh/cpi/logger'
7
+ require 'bosh/cpi/registry_client'
8
+ require 'bosh/cpi/redactor'
@@ -0,0 +1,147 @@
1
+ require 'json'
2
+
3
+ class Bosh::Cpi::Cli
4
+ KNOWN_RPC_METHODS = %w(
5
+ info
6
+ current_vm_id
7
+ create_stemcell
8
+ delete_stemcell
9
+ create_vm
10
+ delete_vm
11
+ has_vm
12
+ reboot_vm
13
+ set_vm_metadata
14
+ set_disk_metadata
15
+ create_disk
16
+ has_disk
17
+ delete_disk
18
+ attach_disk
19
+ detach_disk
20
+ snapshot_disk
21
+ delete_snapshot
22
+ get_disks
23
+ resize_disk
24
+ ping
25
+ calculate_vm_cloud_properties
26
+ create_subnet
27
+ delete_subnet
28
+ has_subnet
29
+ set_subnet_metadata
30
+ ).freeze
31
+
32
+ RPC_METHOD_TO_RUBY_METHOD = {
33
+ 'has_vm' => 'has_vm?',
34
+ 'has_disk' => 'has_disk?',
35
+ }.freeze
36
+
37
+ INVALID_CALL_ERROR_TYPE = 'InvalidCall'.freeze
38
+ UNKNOWN_ERROR_TYPE = 'Unknown'.freeze
39
+
40
+ def initialize(cpi, logs_string_io, result_io)
41
+ @cpi = cpi
42
+ @logs_string_io = logs_string_io
43
+ @result_io = result_io
44
+ @logger = Bosh::Cpi::Logger.new(STDERR)
45
+ end
46
+
47
+ def run(json)
48
+ begin
49
+ request = JSON.load(json)
50
+ rescue JSON::ParserError => e
51
+ return error_response(INVALID_CALL_ERROR_TYPE, "Request cannot be deserialized, details: #{e.message}", false, e.backtrace)
52
+ end
53
+
54
+ method = request['method']
55
+ unless method.is_a?(String)
56
+ return error_response(INVALID_CALL_ERROR_TYPE, "Method must be a String, got: '#{method.inspect}'", false)
57
+ end
58
+
59
+ unless KNOWN_RPC_METHODS.include?(method)
60
+ return error_response(Bosh::Clouds::NotImplemented.name, "Method is not known, got: '#{method}'", false)
61
+ end
62
+
63
+ arguments = request['arguments']
64
+ unless arguments.is_a?(Array)
65
+ return error_response(INVALID_CALL_ERROR_TYPE, "Arguments must be an Array", false)
66
+ end
67
+
68
+ context = request['context']
69
+ unless context.is_a?(Hash) && context['director_uuid'].is_a?(String)
70
+ return error_response(INVALID_CALL_ERROR_TYPE, "Request should include context with director uuid", false)
71
+ end
72
+
73
+ req_id = context['request_id']
74
+ @logger.set_request_id(req_id)
75
+
76
+ configure_director(context['director_uuid'])
77
+
78
+ ruby_method = RPC_METHOD_TO_RUBY_METHOD[method] || method
79
+
80
+ begin
81
+ start_time = Time.now.utc
82
+ @logger.info("Starting #{method}...")
83
+
84
+ cpi = @cpi.call(context)
85
+
86
+ result = cpi.public_send(ruby_method, *arguments)
87
+ rescue Bosh::Clouds::RetriableCloudError => e
88
+ return error_response(error_name(e), e.message, e.ok_to_retry, e.backtrace)
89
+ rescue Bosh::Clouds::CloudError, Bosh::Clouds::CpiError => e
90
+ return error_response(error_name(e), e.message, false, e.backtrace)
91
+ rescue ArgumentError => e
92
+ return error_response(INVALID_CALL_ERROR_TYPE, "Arguments are not correct, details: '#{e.message}'", false, e.backtrace)
93
+ rescue Exception => e
94
+ return error_response(UNKNOWN_ERROR_TYPE, e.message, false, e.backtrace)
95
+ ensure
96
+ end_time = Time.now.utc
97
+ @logger.info("Finished #{method} in #{(end_time - start_time).round(2)} seconds")
98
+ end
99
+
100
+ result_response(result)
101
+ end
102
+
103
+ private
104
+
105
+ def configure_director(director_uuid)
106
+ Bosh::Clouds::Config.uuid = director_uuid
107
+ end
108
+
109
+ def error_response(type, message, ok_to_retry, bt=[])
110
+ if !bt.empty?
111
+ @logs_string_io.print("Rescued #{type}: #{message}. backtrace: #{bt.join("\n")}")
112
+ end
113
+
114
+ hash = {
115
+ result: nil,
116
+ error: {
117
+ type: type,
118
+ message: message,
119
+ ok_to_retry: ok_to_retry,
120
+ },
121
+ log: encode_string_as_utf8(@logs_string_io.string)
122
+ }
123
+ @result_io.print(JSON.dump(hash)); nil
124
+ end
125
+
126
+ def result_response(result)
127
+ hash = {
128
+ result: result,
129
+ error: nil,
130
+ log: encode_string_as_utf8(@logs_string_io.string)
131
+ }
132
+ @result_io.print(JSON.dump(hash)); nil
133
+ end
134
+
135
+ def error_name(error)
136
+ error.class.name
137
+ end
138
+
139
+ def encode_string_as_utf8(src)
140
+ log = @logs_string_io.string.force_encoding(Encoding::UTF_8)
141
+ unless log.valid_encoding?
142
+ # the src encoding hint of Encoding::BINARY is only required for ruby 1.9.3
143
+ log = @logs_string_io.string.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace, invalid: :replace)
144
+ end
145
+ log
146
+ end
147
+ end
@@ -0,0 +1,5 @@
1
+ require 'bosh/cpi'
2
+
3
+ module Bosh::Cpi
4
+ module CompatibilityHelpers; end
5
+ end
@@ -0,0 +1,15 @@
1
+ require 'bosh/cpi/compatibility_helpers'
2
+
3
+ module Bosh::Cpi::CompatibilityHelpers
4
+ def it_can_delete_non_existent_vm(vm_cid='vm-cid')
5
+ describe "delete_vm (deleting non existent vm)" do
6
+ context "when VM is not present" do
7
+ it "raises VMNotFound error" do
8
+ expect {
9
+ cpi.delete_vm(vm_cid)
10
+ }.to raise_error(Bosh::Clouds::VMNotFound, "VM '#{vm_cid}' not found")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'logger'
2
+
3
+ class Bosh::Cpi::Logger < Logger
4
+
5
+ def initialize(log_device)
6
+ super(log_device)
7
+ end
8
+
9
+ def set_request_id(req_id)
10
+ original_formatter = Logger::Formatter.new
11
+ self.formatter = proc { |severity, datetime, progname, msg|
12
+ original_formatter.call(severity, datetime, "[req_id #{req_id}]#{progname}", msg)
13
+ }
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module Bosh::Cpi
2
+ class Redactor
3
+
4
+ REDACTED = '<redacted>'
5
+
6
+ def self.clone_and_redact(hash, *paths)
7
+ begin
8
+ hash = JSON.parse(hash.to_json)
9
+ rescue
10
+ return nil
11
+ end
12
+
13
+ redact!(hash, *paths)
14
+ end
15
+
16
+ def self.redact!(hash, *json_paths)
17
+ json_paths.each do |json_path|
18
+ properties = json_path.split('.')
19
+ property_to_redact = properties.pop
20
+
21
+ target_hash = properties.reduce(hash, &fetch_property)
22
+ target_hash[property_to_redact] = REDACTED if target_hash.has_key? property_to_redact
23
+ end
24
+
25
+ hash
26
+ end
27
+
28
+ def self.fetch_property
29
+ -> (hash, property) { hash.fetch(property, {})}
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,107 @@
1
+ require 'cloud/errors'
2
+ require 'httpclient'
3
+ require 'base64'
4
+ require 'json'
5
+
6
+ module Bosh::Cpi
7
+ class RegistryClient
8
+ attr_reader :endpoint
9
+ attr_reader :user
10
+ attr_reader :password
11
+
12
+ def initialize(endpoint, user, password)
13
+ @endpoint = endpoint
14
+
15
+ unless @endpoint =~ /^http:\/\//
16
+ @endpoint = "http://#{@endpoint}"
17
+ end
18
+
19
+ @user = user
20
+ @password = password
21
+
22
+ auth = Base64.encode64("#{@user}:#{@password}").gsub("\n", '')
23
+
24
+ @headers = {
25
+ "Accept" => 'application/json',
26
+ "Authorization" => "Basic #{auth}"
27
+ }
28
+
29
+ @client = HTTPClient.new
30
+ end
31
+
32
+ ##
33
+ # Update instance settings in the registry
34
+ # @param [String] instance_id EC2 instance id
35
+ # @param [Hash] settings New agent settings
36
+ # @return [Boolean]
37
+ def update_settings(instance_id, settings)
38
+ unless settings.is_a?(Hash)
39
+ raise ArgumentError, "Invalid settings format, Hash expected, #{settings.class} given"
40
+ end
41
+
42
+ payload = JSON.dump(settings)
43
+ url = "#{@endpoint}/instances/#{instance_id}/settings"
44
+ put_headers = @headers.merge('Content-Type' => 'application/json')
45
+
46
+ response = @client.put(url, {:body => payload, :header => put_headers})
47
+
48
+ unless HTTP::Status.successful?(response.status)
49
+ cloud_error("Cannot update settings for '#{instance_id}', got HTTP #{response.status}")
50
+ end
51
+
52
+ true
53
+ end
54
+
55
+ ##
56
+ # Read instance settings from the registry
57
+ # @param [String] instance_id EC2 instance id
58
+ # @return [Hash] Agent settings
59
+ def read_settings(instance_id)
60
+ url = "#{@endpoint}/instances/#{instance_id}/settings"
61
+
62
+ response = @client.get(url, {:header => @headers})
63
+
64
+ if response.status != 200
65
+ cloud_error("Cannot read settings for '#{instance_id}', got HTTP #{response.status}")
66
+ end
67
+
68
+ body = JSON.load(response.body)
69
+
70
+ unless body.is_a?(Hash)
71
+ cloud_error("Invalid registry response, Hash expected, got #{body.class}: #{body}")
72
+ end
73
+
74
+ settings = JSON.load(body["settings"])
75
+
76
+ unless settings.is_a?(Hash)
77
+ cloud_error("Invalid settings format, Hash expected, got #{settings.class}: #{settings}")
78
+ end
79
+
80
+ settings
81
+ rescue JSON::ParserError => e
82
+ cloud_error("Cannot parse settings for '#{instance_id}': #{e.message}")
83
+ end
84
+
85
+ ##
86
+ # Delete instance settings from the registry
87
+ # @param [String] instance_id EC2 instance id
88
+ # @return [Boolean]
89
+ def delete_settings(instance_id)
90
+ url = "#{@endpoint}/instances/#{instance_id}/settings"
91
+
92
+ response = @client.delete(url, {:header => @headers})
93
+
94
+ unless [200, 404].include? response.status
95
+ cloud_error("Cannot delete settings for '#{instance_id}', got HTTP #{response.status}")
96
+ end
97
+
98
+ true
99
+ end
100
+
101
+ private
102
+
103
+ def cloud_error(message)
104
+ raise Bosh::Clouds::CloudError, message
105
+ end
106
+ end
107
+ end
@@ -0,0 +1 @@
1
+ Dir.glob(File.expand_path('tasks/**/*.rake', File.dirname(__FILE__))).each { |r| import r }
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
3
+
4
+ namespace :spec do
5
+ desc 'Run VM lifecycle specs'
6
+ RSpec::Core::RakeTask.new(:lifecycle) do |t|
7
+ t.pattern = 'spec/integration'
8
+ t.rspec_opts = %w(--format documentation --color)
9
+ end
10
+ end
data/lib/cloud.rb ADDED
@@ -0,0 +1,259 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh; module Clouds; end; end
4
+
5
+ require "forwardable"
6
+
7
+ require "cloud/config"
8
+ require "cloud/errors"
9
+
10
+ module Bosh
11
+
12
+ ##
13
+ # CPI - Cloud Provider Interface, used for interfacing with various IaaS APIs.
14
+ #
15
+ # Key terms:
16
+ # Stemcell: template used for creating VMs (shouldn't be powered on)
17
+ # VM: VM created from a stemcell with custom settings (networking and resources)
18
+ # Disk: volume that can be attached and detached from the VMs,
19
+ # never attached to more than a single VM at one time
20
+ class Cloud
21
+
22
+ ##
23
+ # Cloud initialization
24
+ #
25
+ # @param [Hash] options cloud options
26
+ def initialize(options)
27
+ end
28
+
29
+ ## Information about cpi
30
+ #
31
+ # Sample info response:
32
+ # {"stemcell_formats" =>
33
+ # ["aws-raw", "aws-light"]
34
+ # }
35
+ # @return [Hash] information about cpi, currently stemcell formats, which are supported
36
+ def info
37
+ not_implemented(:info)
38
+ end
39
+
40
+ ##
41
+ # Get the vm_id of this host
42
+ #
43
+ # @return [String] opaque id later used by other methods of the CPI
44
+ def current_vm_id
45
+ not_implemented(:current_vm_id)
46
+ end
47
+
48
+ ##
49
+ # Creates a stemcell
50
+ #
51
+ # @param [String] image_path path to an opaque blob containing the stemcell image
52
+ # @param [Hash] cloud_properties properties required for creating this template
53
+ # specific to a CPI
54
+ # @return [String] opaque id later used by {#create_vm} and {#delete_stemcell}
55
+ def create_stemcell(image_path, cloud_properties)
56
+ not_implemented(:create_stemcell)
57
+ end
58
+
59
+ ##
60
+ # Deletes a stemcell
61
+ #
62
+ # @param [String] stemcell stemcell id that was once returned by {#create_stemcell}
63
+ # @return [void]
64
+ def delete_stemcell(stemcell_id)
65
+ not_implemented(:delete_stemcell)
66
+ end
67
+
68
+ ##
69
+ # Creates a VM - creates (and powers on) a VM from a stemcell with the proper resources
70
+ # and on the specified network. When disk locality is present the VM will be placed near
71
+ # the provided disk so it won't have to move when the disk is attached later.
72
+ #
73
+ # Sample networking config:
74
+ # {"network_a" =>
75
+ # {
76
+ # "netmask" => "255.255.248.0",
77
+ # "ip" => "172.30.41.40",
78
+ # "gateway" => "172.30.40.1",
79
+ # "dns" => ["172.30.22.153", "172.30.22.154"],
80
+ # "cloud_properties" => {"name" => "VLAN444"}
81
+ # }
82
+ # }
83
+ #
84
+ # Sample resource pool config (CPI specific):
85
+ # {
86
+ # "ram" => 512,
87
+ # "disk" => 512,
88
+ # "cpu" => 1
89
+ # }
90
+ # or similar for EC2:
91
+ # {"name" => "m1.small"}
92
+ #
93
+ # @param [String] agent_id UUID for the agent that will be used later on by the director
94
+ # to locate and talk to the agent
95
+ # @param [String] stemcell stemcell id that was once returned by {#create_stemcell}
96
+ # @param [Hash] resource_pool cloud specific properties describing the resources needed
97
+ # for this VM
98
+ # @param [Hash] networks list of networks and their settings needed for this VM
99
+ # @param [String, Array] disk_locality disk id(s) if known of the disk(s) that will be
100
+ # attached to this vm
101
+ # @param [Hash] env environment that will be passed to this vm
102
+ # @return [String] opaque id later used by {#attach_disk}, {#detach_disk} and {#delete_vm}
103
+ def create_vm(agent_id, stemcell_id, resource_pool,
104
+ networks, disk_locality, env)
105
+ not_implemented(:create_vm)
106
+ end
107
+
108
+ ##
109
+ # Deletes a VM. If the VM has already been deleted, this call returns normally and has no effect.
110
+ #
111
+ # @param [String] vm vm id that was once returned by {#create_vm}
112
+ # @return [void]
113
+ def delete_vm(vm_id)
114
+ not_implemented(:delete_vm)
115
+ end
116
+
117
+ ##
118
+ # Checks if a VM exists
119
+ #
120
+ # @param [String] vm vm id that was once returned by {#create_vm}
121
+ # @return [Boolean] True if the vm exists
122
+ def has_vm?(vm_id)
123
+ not_implemented(:has_vm?)
124
+ end
125
+
126
+ ##
127
+ # Checks if a disk exists
128
+ #
129
+ # @param [String] disk disk_id that was once returned by {#create_disk}
130
+ # @return [Boolean] True if the disk exists
131
+ def has_disk?(disk_id)
132
+ not_implemented(:has_disk?)
133
+ end
134
+
135
+ ##
136
+ # Reboots a VM
137
+ #
138
+ # @param [String] vm vm id that was once returned by {#create_vm}
139
+ # @param [Optional, Hash] CPI specific options (e.g hard/soft reboot)
140
+ # @return [void]
141
+ def reboot_vm(vm_id)
142
+ not_implemented(:reboot_vm)
143
+ end
144
+
145
+ ##
146
+ # Set metadata for a VM
147
+ #
148
+ # Optional. Implement to provide more information for the IaaS.
149
+ #
150
+ # @param [String] vm vm id that was once returned by {#create_vm}
151
+ # @param [Hash] metadata metadata key/value pairs
152
+ # @return [void]
153
+ def set_vm_metadata(vm, metadata)
154
+ not_implemented(:set_vm_metadata)
155
+ end
156
+
157
+ ##
158
+ # Set metadata for a disk
159
+ #
160
+ # Optional. Implement to provide more information for the IaaS.
161
+ #
162
+ # @param [String] disk_id disk id that was once returned by {#create_disk}
163
+ # @param [Hash] metadata metadata key/value pairs
164
+ # @return [void]
165
+ def set_disk_metadata(disk_id, metadata)
166
+ not_implemented(:set_disk_metadata)
167
+ end
168
+
169
+ ##
170
+ # Creates a disk (possibly lazily) that will be attached later to a VM. When
171
+ # VM locality is specified the disk will be placed near the VM so it won't have to move
172
+ # when it's attached later.
173
+ #
174
+ # @param [Integer] size disk size in MB
175
+ # @param [Hash] cloud_properties properties required for creating this disk
176
+ # specific to a CPI
177
+ # @param [String] vm_locality vm id if known of the VM that this disk will
178
+ # be attached to
179
+ # @return [String] opaque id later used by {#attach_disk}, {#detach_disk}, and {#delete_disk}
180
+ def create_disk(size, cloud_properties, vm_locality)
181
+ not_implemented(:create_disk)
182
+ end
183
+
184
+ ##
185
+ # Deletes a disk
186
+ # Will raise an exception if the disk is attached to a VM
187
+ #
188
+ # @param [String] disk disk id that was once returned by {#create_disk}
189
+ # @return [void]
190
+ def delete_disk(disk_id)
191
+ not_implemented(:delete_disk)
192
+ end
193
+
194
+ # Attaches a disk
195
+ # @param [String] vm vm id that was once returned by {#create_vm}
196
+ # @param [String] disk disk id that was once returned by {#create_disk}
197
+ # @return [void]
198
+ def attach_disk(vm_id, disk_id)
199
+ not_implemented(:attach_disk)
200
+ end
201
+
202
+ # Take snapshot of disk
203
+ # @param [String] disk_id disk id of the disk to take the snapshot of
204
+ # @param [Hash] metadata metadata key/value pairs
205
+ # @return [String] snapshot id
206
+ def snapshot_disk(disk_id, metadata)
207
+ not_implemented(:snapshot_disk)
208
+ end
209
+
210
+ # Delete a disk snapshot
211
+ # @param [String] snapshot_id snapshot id to delete
212
+ # @return [void]
213
+ def delete_snapshot(snapshot_id)
214
+ not_implemented(:delete_snapshot)
215
+ end
216
+
217
+ # Detaches a disk
218
+ # @param [String] vm vm id that was once returned by {#create_vm}
219
+ # @param [String] disk disk id that was once returned by {#create_disk}
220
+ # @return [void]
221
+ def detach_disk(vm_id, disk_id)
222
+ not_implemented(:detach_disk)
223
+ end
224
+
225
+ # List the attached disks of the VM.
226
+ # @param [String] vm_id is the CPI-standard vm_id (eg, returned from current_vm_id)
227
+ # @return [array[String]] list of opaque disk_ids that can be used with the
228
+ # other disk-related methods on the CPI
229
+ def get_disks(vm_id)
230
+ not_implemented(:get_disks)
231
+ end
232
+
233
+ ##
234
+ # Resizes an existing disk
235
+ #
236
+ # @param [String] disk_id disk id
237
+ # @param [Integer] new_size disk size in MiB
238
+ # @return [void]
239
+ def resize_disk(disk_id, new_size)
240
+ not_implemented(:resize_disk)
241
+ end
242
+
243
+ # Specify VM's hardware resources
244
+ # @param [Hash] vm_properties (typically cpu, ram, ephemeral_disk_size)
245
+ # @return [Hash] opaque description of the VM's configuration that
246
+ # can be used with {#create_vm}
247
+ def calculate_vm_cloud_properties(vm_properties)
248
+ not_implemented(:calculate_vm_cloud_properties)
249
+ end
250
+
251
+ private
252
+
253
+ def not_implemented(method)
254
+ raise Bosh::Clouds::NotImplemented,
255
+ "'#{method}' is not implemented by #{self.class}"
256
+ end
257
+
258
+ end
259
+ end
@@ -0,0 +1,17 @@
1
+ require 'forwardable'
2
+
3
+ module Bosh::Clouds
4
+ class Config
5
+
6
+ class << self
7
+ extend Forwardable
8
+ def_delegators :@delegate, :db, :logger, :uuid, :uuid=, :task_checkpoint, :cpi_task_log
9
+ end
10
+
11
+ # @param [Bosh::Director::Config] config director config file
12
+ def self.configure(config)
13
+ @delegate = config
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Bosh::Clouds
2
+ class CpiError < StandardError; end
3
+ class NotImplemented < CpiError; end
4
+ class NotSupported < CpiError; end
5
+
6
+ class CloudError < StandardError; end
7
+ class VMNotFound < CloudError; end
8
+
9
+ class RetriableCloudError < CloudError
10
+ attr_accessor :ok_to_retry
11
+
12
+ def initialize(ok_to_retry)
13
+ @ok_to_retry = ok_to_retry
14
+ end
15
+ end
16
+
17
+ class NoDiskSpace < RetriableCloudError; end
18
+ class DiskNotAttached < RetriableCloudError; end
19
+ class DiskNotFound < RetriableCloudError; end
20
+ class VMCreationFailed < RetriableCloudError; end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Bosh
2
+ module Clouds
3
+ VERSION = '0.0.0'
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bosh_cpi_networking
3
+ version: !ruby/object:Gem::Version
4
+ version: '2.5'
5
+ platform: ruby
6
+ authors:
7
+ - VMware
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: membrane
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.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.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: httpclient
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.8.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.8.3
41
+ description: BOSH CPI with network management support
42
+ email: support@cloudfoundry.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/bosh/cpi.rb
48
+ - lib/bosh/cpi/cli.rb
49
+ - lib/bosh/cpi/compatibility_helpers.rb
50
+ - lib/bosh/cpi/compatibility_helpers/delete_vm.rb
51
+ - lib/bosh/cpi/logger.rb
52
+ - lib/bosh/cpi/redactor.rb
53
+ - lib/bosh/cpi/registry_client.rb
54
+ - lib/bosh/cpi/tasks.rb
55
+ - lib/bosh/cpi/tasks/spec.rake
56
+ - lib/cloud.rb
57
+ - lib/cloud/config.rb
58
+ - lib/cloud/errors.rb
59
+ - lib/cloud/version.rb
60
+ homepage: https://github.com/medvedzver/bosh-cpi-ruby
61
+ licenses:
62
+ - Apache 2.0
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.9.3
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.5.1
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: BOSH CPI with network management support
84
+ test_files: []