bosh_cpi 1.3262.24.0 → 2.0.0
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 +4 -4
- metadata +4 -60
- data/lib/bosh/cpi/cli.rb +0 -119
- data/lib/bosh/cpi/compatibility_helpers/delete_vm.rb +0 -15
- data/lib/bosh/cpi/compatibility_helpers.rb +0 -5
- data/lib/bosh/cpi/registry_client.rb +0 -106
- data/lib/bosh/cpi/tasks/spec.rake +0 -10
- data/lib/bosh/cpi/tasks.rb +0 -1
- data/lib/bosh/cpi.rb +0 -6
- data/lib/cloud/config.rb +0 -17
- data/lib/cloud/errors.rb +0 -21
- data/lib/cloud/external_cpi.rb +0 -149
- data/lib/cloud/internal_cpi.rb +0 -25
- data/lib/cloud/provider.rb +0 -31
- data/lib/cloud/version.rb +0 -5
- data/lib/cloud.rb +0 -221
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99a4eed7d57155aaab71e8d3d96ba913ca1c3dd7
|
|
4
|
+
data.tar.gz: 989cf2cf09fb1a47addb39348441be1d9f10fb87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc58193908a9b31b1a0eb6d03d6f6a93e8b9fa95c318691d017a5d9853d264c0c37577333c6ab052a54681861507a46a6e8da9cfc29c46a98a524f0e4e73e57f
|
|
7
|
+
data.tar.gz: f415c989376f1cbd0eac4388a7da3ec57964af26467e7d84da3d3217fdf184a4e103d6e3b0a7bb1034a28cb80effa9fa77bfda7fb27d6290426bb97406070cba
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bosh_cpi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- VMware
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-11-
|
|
11
|
+
date: 2016-11-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bosh_common
|
|
@@ -52,68 +52,12 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: 1.8.2
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rake
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: rspec
|
|
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
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rspec-its
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
55
|
description: BOSH CPI
|
|
98
56
|
email: support@cloudfoundry.com
|
|
99
57
|
executables: []
|
|
100
58
|
extensions: []
|
|
101
59
|
extra_rdoc_files: []
|
|
102
|
-
files:
|
|
103
|
-
- lib/bosh/cpi.rb
|
|
104
|
-
- lib/bosh/cpi/cli.rb
|
|
105
|
-
- lib/bosh/cpi/compatibility_helpers.rb
|
|
106
|
-
- lib/bosh/cpi/compatibility_helpers/delete_vm.rb
|
|
107
|
-
- lib/bosh/cpi/registry_client.rb
|
|
108
|
-
- lib/bosh/cpi/tasks.rb
|
|
109
|
-
- lib/bosh/cpi/tasks/spec.rake
|
|
110
|
-
- lib/cloud.rb
|
|
111
|
-
- lib/cloud/config.rb
|
|
112
|
-
- lib/cloud/errors.rb
|
|
113
|
-
- lib/cloud/external_cpi.rb
|
|
114
|
-
- lib/cloud/internal_cpi.rb
|
|
115
|
-
- lib/cloud/provider.rb
|
|
116
|
-
- lib/cloud/version.rb
|
|
60
|
+
files: []
|
|
117
61
|
homepage: https://github.com/cloudfoundry/bosh
|
|
118
62
|
licenses:
|
|
119
63
|
- Apache 2.0
|
|
@@ -134,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
134
78
|
version: '0'
|
|
135
79
|
requirements: []
|
|
136
80
|
rubyforge_project:
|
|
137
|
-
rubygems_version: 2.
|
|
81
|
+
rubygems_version: 2.5.1
|
|
138
82
|
signing_key:
|
|
139
83
|
specification_version: 4
|
|
140
84
|
summary: BOSH CPI
|
data/lib/bosh/cpi/cli.rb
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
|
|
3
|
-
class Bosh::Cpi::Cli
|
|
4
|
-
KNOWN_RPC_METHODS = %w(
|
|
5
|
-
current_vm_id
|
|
6
|
-
create_stemcell
|
|
7
|
-
delete_stemcell
|
|
8
|
-
create_vm
|
|
9
|
-
delete_vm
|
|
10
|
-
has_vm
|
|
11
|
-
reboot_vm
|
|
12
|
-
set_vm_metadata
|
|
13
|
-
create_disk
|
|
14
|
-
has_disk
|
|
15
|
-
delete_disk
|
|
16
|
-
attach_disk
|
|
17
|
-
detach_disk
|
|
18
|
-
snapshot_disk
|
|
19
|
-
delete_snapshot
|
|
20
|
-
get_disks
|
|
21
|
-
ping
|
|
22
|
-
).freeze
|
|
23
|
-
|
|
24
|
-
RPC_METHOD_TO_RUBY_METHOD = {
|
|
25
|
-
'has_vm' => 'has_vm?',
|
|
26
|
-
'has_disk' => 'has_disk?',
|
|
27
|
-
}.freeze
|
|
28
|
-
|
|
29
|
-
INVALID_CALL_ERROR_TYPE = 'InvalidCall'.freeze
|
|
30
|
-
UNKNOWN_ERROR_TYPE = 'Unknown'.freeze
|
|
31
|
-
|
|
32
|
-
def initialize(cpi, logs_string_io, result_io)
|
|
33
|
-
@cpi = cpi
|
|
34
|
-
@logs_string_io = logs_string_io
|
|
35
|
-
@result_io = result_io
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def run(json)
|
|
39
|
-
begin
|
|
40
|
-
request = JSON.load(json)
|
|
41
|
-
rescue JSON::ParserError => e
|
|
42
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Request cannot be deserialized, details: #{e.message}", false, e.backtrace)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
method = request['method']
|
|
46
|
-
unless method.is_a?(String)
|
|
47
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Method must be a String, got: '#{method.inspect}'", false)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
unless KNOWN_RPC_METHODS.include?(method)
|
|
51
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Method is not known, got: '#{method}'", false)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
arguments = request['arguments']
|
|
55
|
-
unless arguments.is_a?(Array)
|
|
56
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Arguments must be an Array, got: '#{arguments.inspect}'", false)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
context = request['context']
|
|
60
|
-
unless context.is_a?(Hash) && context['director_uuid'].is_a?(String)
|
|
61
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Request should include context with director uuid, got: '#{context.inspect}'", false)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
configure_director(context['director_uuid'])
|
|
65
|
-
|
|
66
|
-
ruby_method = RPC_METHOD_TO_RUBY_METHOD[method] || method
|
|
67
|
-
|
|
68
|
-
begin
|
|
69
|
-
cpi = @cpi.call
|
|
70
|
-
result = cpi.public_send(ruby_method, *arguments)
|
|
71
|
-
rescue Bosh::Clouds::RetriableCloudError => e
|
|
72
|
-
return error_response(error_name(e), e.message, e.ok_to_retry, e.backtrace)
|
|
73
|
-
rescue Bosh::Clouds::CloudError, Bosh::Clouds::CpiError => e
|
|
74
|
-
return error_response(error_name(e), e.message, false, e.backtrace)
|
|
75
|
-
rescue ArgumentError => e
|
|
76
|
-
return error_response(INVALID_CALL_ERROR_TYPE, "Arguments are not correct, details: '#{e.message}'", false, e.backtrace)
|
|
77
|
-
rescue Exception => e
|
|
78
|
-
return error_response(UNKNOWN_ERROR_TYPE, e.message, false, e.backtrace)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
result_response(result)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
def configure_director(director_uuid)
|
|
87
|
-
Bosh::Clouds::Config.uuid = director_uuid
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def error_response(type, message, ok_to_retry, bt=[])
|
|
91
|
-
if !bt.empty?
|
|
92
|
-
@logs_string_io.print("Rescued #{type}: #{message}. backtrace: #{bt.join("\n")}")
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
hash = {
|
|
96
|
-
result: nil,
|
|
97
|
-
error: {
|
|
98
|
-
type: type,
|
|
99
|
-
message: message,
|
|
100
|
-
ok_to_retry: ok_to_retry,
|
|
101
|
-
},
|
|
102
|
-
log: @logs_string_io.string.force_encoding(Encoding::UTF_8),
|
|
103
|
-
}
|
|
104
|
-
@result_io.print(JSON.dump(hash)); nil
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def result_response(result)
|
|
108
|
-
hash = {
|
|
109
|
-
result: result,
|
|
110
|
-
error: nil,
|
|
111
|
-
log: @logs_string_io.string.force_encoding(Encoding::UTF_8),
|
|
112
|
-
}
|
|
113
|
-
@result_io.print(JSON.dump(hash)); nil
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def error_name(error)
|
|
117
|
-
error.class.name
|
|
118
|
-
end
|
|
119
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
|
@@ -1,106 +0,0 @@
|
|
|
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
|
-
|
|
45
|
-
response = @client.put(url, {:body => payload, :header => @headers})
|
|
46
|
-
|
|
47
|
-
unless HTTP::Status.successful?(response.status)
|
|
48
|
-
cloud_error("Cannot update settings for '#{instance_id}', got HTTP #{response.status}")
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
true
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
##
|
|
55
|
-
# Read instance settings from the registry
|
|
56
|
-
# @param [String] instance_id EC2 instance id
|
|
57
|
-
# @return [Hash] Agent settings
|
|
58
|
-
def read_settings(instance_id)
|
|
59
|
-
url = "#{@endpoint}/instances/#{instance_id}/settings"
|
|
60
|
-
|
|
61
|
-
response = @client.get(url, {:header => @headers})
|
|
62
|
-
|
|
63
|
-
if response.status != 200
|
|
64
|
-
cloud_error("Cannot read settings for '#{instance_id}', got HTTP #{response.status}")
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
body = JSON.load(response.body)
|
|
68
|
-
|
|
69
|
-
unless body.is_a?(Hash)
|
|
70
|
-
cloud_error("Invalid registry response, Hash expected, got #{body.class}: #{body}")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
settings = JSON.load(body["settings"])
|
|
74
|
-
|
|
75
|
-
unless settings.is_a?(Hash)
|
|
76
|
-
cloud_error("Invalid settings format, Hash expected, got #{settings.class}: #{settings}")
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
settings
|
|
80
|
-
rescue JSON::ParserError => e
|
|
81
|
-
cloud_error("Cannot parse settings for '#{instance_id}': #{e.message}")
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
##
|
|
85
|
-
# Delete instance settings from the registry
|
|
86
|
-
# @param [String] instance_id EC2 instance id
|
|
87
|
-
# @return [Boolean]
|
|
88
|
-
def delete_settings(instance_id)
|
|
89
|
-
url = "#{@endpoint}/instances/#{instance_id}/settings"
|
|
90
|
-
|
|
91
|
-
response = @client.delete(url, {:header => @headers})
|
|
92
|
-
|
|
93
|
-
unless [200, 404].include? response.status
|
|
94
|
-
cloud_error("Cannot delete settings for '#{instance_id}', got HTTP #{response.status}")
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
true
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
private
|
|
101
|
-
|
|
102
|
-
def cloud_error(message)
|
|
103
|
-
raise Bosh::Clouds::CloudError, message
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
data/lib/bosh/cpi/tasks.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Dir.glob(File.expand_path('tasks/**/*.rake', File.dirname(__FILE__))).each { |r| import r }
|
data/lib/bosh/cpi.rb
DELETED
data/lib/cloud/config.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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
|
data/lib/cloud/errors.rb
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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
|
data/lib/cloud/external_cpi.rb
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
require 'membrane'
|
|
2
|
-
require 'open3'
|
|
3
|
-
|
|
4
|
-
module Bosh::Clouds
|
|
5
|
-
class ExternalCpi
|
|
6
|
-
# Raised when the external CPI executable returns an error unknown to director
|
|
7
|
-
class UnknownError < StandardError; end
|
|
8
|
-
|
|
9
|
-
# Raised when the external CPI executable returns nil or invalid JSON format to director
|
|
10
|
-
class InvalidResponse < StandardError; end
|
|
11
|
-
|
|
12
|
-
# Raised when the external CPI bin/cpi is not executable
|
|
13
|
-
class NonExecutable < StandardError; end
|
|
14
|
-
|
|
15
|
-
KNOWN_RPC_ERRORS = %w(
|
|
16
|
-
Bosh::Clouds::CpiError
|
|
17
|
-
Bosh::Clouds::NotSupported
|
|
18
|
-
Bosh::Clouds::NotImplemented
|
|
19
|
-
|
|
20
|
-
Bosh::Clouds::CloudError
|
|
21
|
-
Bosh::Clouds::VMNotFound
|
|
22
|
-
|
|
23
|
-
Bosh::Clouds::NoDiskSpace
|
|
24
|
-
Bosh::Clouds::DiskNotAttached
|
|
25
|
-
Bosh::Clouds::DiskNotFound
|
|
26
|
-
Bosh::Clouds::VMCreationFailed
|
|
27
|
-
).freeze
|
|
28
|
-
|
|
29
|
-
RESPONSE_SCHEMA = Membrane::SchemaParser.parse do
|
|
30
|
-
{
|
|
31
|
-
'result' => any,
|
|
32
|
-
'error' => enum(nil,
|
|
33
|
-
{ 'type' => String,
|
|
34
|
-
'message' => String,
|
|
35
|
-
'ok_to_retry' => bool
|
|
36
|
-
}
|
|
37
|
-
),
|
|
38
|
-
'log' => String
|
|
39
|
-
}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def initialize(cpi_path, director_uuid)
|
|
43
|
-
@cpi_path = cpi_path
|
|
44
|
-
@director_uuid = director_uuid
|
|
45
|
-
@logger = Config.logger
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def current_vm_id(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
49
|
-
def create_stemcell(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
50
|
-
def delete_stemcell(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
51
|
-
def create_vm(*arguments) invoke_cpi_method(__method__.to_s, *arguments); end
|
|
52
|
-
def delete_vm(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
53
|
-
def has_vm?(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
54
|
-
def reboot_vm(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
55
|
-
def set_vm_metadata(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
56
|
-
def create_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
57
|
-
def has_disk?(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
58
|
-
def delete_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
59
|
-
def attach_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
60
|
-
def detach_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
61
|
-
def snapshot_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
62
|
-
def delete_snapshot(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
63
|
-
def get_disks(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
64
|
-
def ping(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
|
|
65
|
-
|
|
66
|
-
private
|
|
67
|
-
|
|
68
|
-
def invoke_cpi_method(method_name, *arguments)
|
|
69
|
-
request = JSON.dump({
|
|
70
|
-
'method' => method_name.gsub(/\?$/,''),
|
|
71
|
-
'arguments' => arguments,
|
|
72
|
-
'context' => {
|
|
73
|
-
'director_uuid' => @director_uuid
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
env = {'PATH' => '/usr/sbin:/usr/bin:/sbin:/bin', 'TMPDIR' => ENV['TMPDIR']}
|
|
78
|
-
cpi_exec_path = checked_cpi_exec_path
|
|
79
|
-
|
|
80
|
-
@logger.debug("External CPI sending request: #{request} with command: #{cpi_exec_path}")
|
|
81
|
-
cpi_response, stderr, exit_status = Open3.capture3(env, cpi_exec_path, stdin_data: request, unsetenv_others: true)
|
|
82
|
-
@logger.debug("External CPI got response: #{cpi_response}, err: #{stderr}, exit_status: #{exit_status}")
|
|
83
|
-
|
|
84
|
-
parsed_response = parsed_response(cpi_response)
|
|
85
|
-
validate_response(parsed_response)
|
|
86
|
-
|
|
87
|
-
if parsed_response['error']
|
|
88
|
-
handle_error(parsed_response['error'])
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
save_cpi_log(parsed_response['log'])
|
|
92
|
-
save_cpi_log(stderr)
|
|
93
|
-
|
|
94
|
-
parsed_response['result']
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def checked_cpi_exec_path
|
|
98
|
-
unless File.executable?(@cpi_path)
|
|
99
|
-
raise NonExecutable, "Failed to run cpi: '#{@cpi_path}' is not executable"
|
|
100
|
-
end
|
|
101
|
-
@cpi_path
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def handle_error(error_response)
|
|
105
|
-
error_type = error_response['type']
|
|
106
|
-
error_message = error_response['message']
|
|
107
|
-
unless KNOWN_RPC_ERRORS.include?(error_type)
|
|
108
|
-
raise UnknownError, "Unknown CPI error '#{error_type}' with message '#{error_message}'"
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
error_class = constantize(error_type)
|
|
112
|
-
|
|
113
|
-
if error_class <= RetriableCloudError
|
|
114
|
-
error = error_class.new(error_response['ok_to_retry'])
|
|
115
|
-
else
|
|
116
|
-
error = error_class.new(error_message)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
raise error, error_message
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def save_cpi_log(output)
|
|
123
|
-
# cpi log path is set up at the beginning of every task in Config
|
|
124
|
-
# see JobRunner#setup_task_logging
|
|
125
|
-
File.open(Config.cpi_task_log, 'a') do |f|
|
|
126
|
-
f.write(output)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def parsed_response(input)
|
|
131
|
-
begin
|
|
132
|
-
JSON.load(input)
|
|
133
|
-
rescue JSON::ParserError => e
|
|
134
|
-
raise InvalidResponse, "Invalid CPI response - ParserError - #{e.message}"
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def validate_response(response)
|
|
139
|
-
RESPONSE_SCHEMA.validate(response)
|
|
140
|
-
rescue Membrane::SchemaValidationError => e
|
|
141
|
-
raise InvalidResponse, "Invalid CPI response - SchemaValidationError: #{e.message}"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def constantize(camel_cased_word)
|
|
145
|
-
error_name = camel_cased_word.split('::').last
|
|
146
|
-
Bosh::Clouds.const_get(error_name)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
data/lib/cloud/internal_cpi.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
module Bosh::Clouds
|
|
2
|
-
class InternalCpi
|
|
3
|
-
def initialize(cloud)
|
|
4
|
-
@cloud = cloud
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
def method_missing(method_sym, *arguments, &block)
|
|
10
|
-
invoke_cpi_method(method_sym, arguments)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def respond_to?(method_sym)
|
|
14
|
-
cloud.respond_to?(method_sym)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def cloud
|
|
18
|
-
@cloud
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def invoke_cpi_method(method_sym, arguments)
|
|
22
|
-
cloud.send(method_sym, *JSON.parse(JSON.dump(arguments)))
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
data/lib/cloud/provider.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
module Bosh::Clouds
|
|
2
|
-
class Provider
|
|
3
|
-
def self.create(cloud_config, director_uuid)
|
|
4
|
-
if cloud_config.has_key?('provider')
|
|
5
|
-
ExternalCpiProvider.create(cloud_config['provider']['path'], director_uuid)
|
|
6
|
-
else
|
|
7
|
-
InternalCpiProvider.create(cloud_config['plugin'], cloud_config['properties'])
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
class InternalCpiProvider
|
|
15
|
-
def self.create(plugin, options)
|
|
16
|
-
begin
|
|
17
|
-
require "cloud/#{plugin}"
|
|
18
|
-
rescue LoadError => error
|
|
19
|
-
raise CloudError, "Could not load Cloud Provider Plugin: #{plugin}, with error #{error.inspect}"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
InternalCpi.new(Bosh::Clouds.const_get(plugin.capitalize).new(options))
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
class ExternalCpiProvider
|
|
27
|
-
def self.create(cpi_job_path, director_uuid)
|
|
28
|
-
ExternalCpi.new(cpi_job_path, director_uuid)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
data/lib/cloud/version.rb
DELETED
data/lib/cloud.rb
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
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
|
-
require "cloud/provider"
|
|
10
|
-
require "cloud/external_cpi"
|
|
11
|
-
require "cloud/internal_cpi"
|
|
12
|
-
|
|
13
|
-
module Bosh
|
|
14
|
-
|
|
15
|
-
##
|
|
16
|
-
# CPI - Cloud Provider Interface, used for interfacing with various IaaS APIs.
|
|
17
|
-
#
|
|
18
|
-
# Key terms:
|
|
19
|
-
# Stemcell: template used for creating VMs (shouldn't be powered on)
|
|
20
|
-
# VM: VM created from a stemcell with custom settings (networking and resources)
|
|
21
|
-
# Disk: volume that can be attached and detached from the VMs,
|
|
22
|
-
# never attached to more than a single VM at one time
|
|
23
|
-
class Cloud
|
|
24
|
-
|
|
25
|
-
##
|
|
26
|
-
# Cloud initialization
|
|
27
|
-
#
|
|
28
|
-
# @param [Hash] options cloud options
|
|
29
|
-
def initialize(options)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
# Get the vm_id of this host
|
|
34
|
-
#
|
|
35
|
-
# @return [String] opaque id later used by other methods of the CPI
|
|
36
|
-
def current_vm_id
|
|
37
|
-
not_implemented(:current_vm_id)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
##
|
|
41
|
-
# Creates a stemcell
|
|
42
|
-
#
|
|
43
|
-
# @param [String] image_path path to an opaque blob containing the stemcell image
|
|
44
|
-
# @param [Hash] cloud_properties properties required for creating this template
|
|
45
|
-
# specific to a CPI
|
|
46
|
-
# @return [String] opaque id later used by {#create_vm} and {#delete_stemcell}
|
|
47
|
-
def create_stemcell(image_path, cloud_properties)
|
|
48
|
-
not_implemented(:create_stemcell)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
##
|
|
52
|
-
# Deletes a stemcell
|
|
53
|
-
#
|
|
54
|
-
# @param [String] stemcell stemcell id that was once returned by {#create_stemcell}
|
|
55
|
-
# @return [void]
|
|
56
|
-
def delete_stemcell(stemcell_id)
|
|
57
|
-
not_implemented(:delete_stemcell)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
##
|
|
61
|
-
# Creates a VM - creates (and powers on) a VM from a stemcell with the proper resources
|
|
62
|
-
# and on the specified network. When disk locality is present the VM will be placed near
|
|
63
|
-
# the provided disk so it won't have to move when the disk is attached later.
|
|
64
|
-
#
|
|
65
|
-
# Sample networking config:
|
|
66
|
-
# {"network_a" =>
|
|
67
|
-
# {
|
|
68
|
-
# "netmask" => "255.255.248.0",
|
|
69
|
-
# "ip" => "172.30.41.40",
|
|
70
|
-
# "gateway" => "172.30.40.1",
|
|
71
|
-
# "dns" => ["172.30.22.153", "172.30.22.154"],
|
|
72
|
-
# "cloud_properties" => {"name" => "VLAN444"}
|
|
73
|
-
# }
|
|
74
|
-
# }
|
|
75
|
-
#
|
|
76
|
-
# Sample resource pool config (CPI specific):
|
|
77
|
-
# {
|
|
78
|
-
# "ram" => 512,
|
|
79
|
-
# "disk" => 512,
|
|
80
|
-
# "cpu" => 1
|
|
81
|
-
# }
|
|
82
|
-
# or similar for EC2:
|
|
83
|
-
# {"name" => "m1.small"}
|
|
84
|
-
#
|
|
85
|
-
# @param [String] agent_id UUID for the agent that will be used later on by the director
|
|
86
|
-
# to locate and talk to the agent
|
|
87
|
-
# @param [String] stemcell stemcell id that was once returned by {#create_stemcell}
|
|
88
|
-
# @param [Hash] resource_pool cloud specific properties describing the resources needed
|
|
89
|
-
# for this VM
|
|
90
|
-
# @param [Hash] networks list of networks and their settings needed for this VM
|
|
91
|
-
# @param [String, Array] disk_locality disk id(s) if known of the disk(s) that will be
|
|
92
|
-
# attached to this vm
|
|
93
|
-
# @param [Hash] env environment that will be passed to this vm
|
|
94
|
-
# @return [String] opaque id later used by {#attach_disk}, {#detach_disk} and {#delete_vm}
|
|
95
|
-
def create_vm(agent_id, stemcell_id, resource_pool,
|
|
96
|
-
networks, disk_locality, env)
|
|
97
|
-
not_implemented(:create_vm)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
##
|
|
101
|
-
# Deletes a VM. If the VM has already been deleted, this call returns normally and has no effect.
|
|
102
|
-
#
|
|
103
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
104
|
-
# @return [void]
|
|
105
|
-
def delete_vm(vm_id)
|
|
106
|
-
not_implemented(:delete_vm)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
##
|
|
110
|
-
# Checks if a VM exists
|
|
111
|
-
#
|
|
112
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
113
|
-
# @return [Boolean] True if the vm exists
|
|
114
|
-
def has_vm?(vm_id)
|
|
115
|
-
not_implemented(:has_vm?)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
##
|
|
119
|
-
# Checks if a disk exists
|
|
120
|
-
#
|
|
121
|
-
# @param [String] disk disk_id that was once returned by {#create_disk}
|
|
122
|
-
# @return [Boolean] True if the disk exists
|
|
123
|
-
def has_disk?(disk_id)
|
|
124
|
-
not_implemented(:has_disk?)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
##
|
|
128
|
-
# Reboots a VM
|
|
129
|
-
#
|
|
130
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
131
|
-
# @param [Optional, Hash] CPI specific options (e.g hard/soft reboot)
|
|
132
|
-
# @return [void]
|
|
133
|
-
def reboot_vm(vm_id)
|
|
134
|
-
not_implemented(:reboot_vm)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
##
|
|
138
|
-
# Set metadata for a VM
|
|
139
|
-
#
|
|
140
|
-
# Optional. Implement to provide more information for the IaaS.
|
|
141
|
-
#
|
|
142
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
143
|
-
# @param [Hash] metadata metadata key/value pairs
|
|
144
|
-
# @return [void]
|
|
145
|
-
def set_vm_metadata(vm, metadata)
|
|
146
|
-
not_implemented(:set_vm_metadata)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
##
|
|
150
|
-
# Creates a disk (possibly lazily) that will be attached later to a VM. When
|
|
151
|
-
# VM locality is specified the disk will be placed near the VM so it won't have to move
|
|
152
|
-
# when it's attached later.
|
|
153
|
-
#
|
|
154
|
-
# @param [Integer] size disk size in MB
|
|
155
|
-
# @param [Hash] cloud_properties properties required for creating this disk
|
|
156
|
-
# specific to a CPI
|
|
157
|
-
# @param [String] vm_locality vm id if known of the VM that this disk will
|
|
158
|
-
# be attached to
|
|
159
|
-
# @return [String] opaque id later used by {#attach_disk}, {#detach_disk}, and {#delete_disk}
|
|
160
|
-
def create_disk(size, cloud_properties, vm_locality)
|
|
161
|
-
not_implemented(:create_disk)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
##
|
|
165
|
-
# Deletes a disk
|
|
166
|
-
# Will raise an exception if the disk is attached to a VM
|
|
167
|
-
#
|
|
168
|
-
# @param [String] disk disk id that was once returned by {#create_disk}
|
|
169
|
-
# @return [void]
|
|
170
|
-
def delete_disk(disk_id)
|
|
171
|
-
not_implemented(:delete_disk)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# Attaches a disk
|
|
175
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
176
|
-
# @param [String] disk disk id that was once returned by {#create_disk}
|
|
177
|
-
# @return [void]
|
|
178
|
-
def attach_disk(vm_id, disk_id)
|
|
179
|
-
not_implemented(:attach_disk)
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
# Take snapshot of disk
|
|
183
|
-
# @param [String] disk_id disk id of the disk to take the snapshot of
|
|
184
|
-
# @param [Hash] metadata metadata key/value pairs
|
|
185
|
-
# @return [String] snapshot id
|
|
186
|
-
def snapshot_disk(disk_id, metadata)
|
|
187
|
-
not_implemented(:snapshot_disk)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
# Delete a disk snapshot
|
|
191
|
-
# @param [String] snapshot_id snapshot id to delete
|
|
192
|
-
# @return [void]
|
|
193
|
-
def delete_snapshot(snapshot_id)
|
|
194
|
-
not_implemented(:delete_snapshot)
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
# Detaches a disk
|
|
198
|
-
# @param [String] vm vm id that was once returned by {#create_vm}
|
|
199
|
-
# @param [String] disk disk id that was once returned by {#create_disk}
|
|
200
|
-
# @return [void]
|
|
201
|
-
def detach_disk(vm_id, disk_id)
|
|
202
|
-
not_implemented(:detach_disk)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
# List the attached disks of the VM.
|
|
206
|
-
# @param [String] vm_id is the CPI-standard vm_id (eg, returned from current_vm_id)
|
|
207
|
-
# @return [array[String]] list of opaque disk_ids that can be used with the
|
|
208
|
-
# other disk-related methods on the CPI
|
|
209
|
-
def get_disks(vm_id)
|
|
210
|
-
not_implemented(:get_disks)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
private
|
|
214
|
-
|
|
215
|
-
def not_implemented(method)
|
|
216
|
-
raise Bosh::Clouds::NotImplemented,
|
|
217
|
-
"'#{method}' is not implemented by #{self.class}"
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
end
|
|
221
|
-
end
|