bosh_cpi 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99a4eed7d57155aaab71e8d3d96ba913ca1c3dd7
4
- data.tar.gz: 989cf2cf09fb1a47addb39348441be1d9f10fb87
3
+ metadata.gz: 77f9ed40e596e15952e7c43452f19682c0e1ea83
4
+ data.tar.gz: 9939c9c1db5797ee1311541d2e8d34ab63dc6d14
5
5
  SHA512:
6
- metadata.gz: dc58193908a9b31b1a0eb6d03d6f6a93e8b9fa95c318691d017a5d9853d264c0c37577333c6ab052a54681861507a46a6e8da9cfc29c46a98a524f0e4e73e57f
7
- data.tar.gz: f415c989376f1cbd0eac4388a7da3ec57964af26467e7d84da3d3217fdf184a4e103d6e3b0a7bb1034a28cb80effa9fa77bfda7fb27d6290426bb97406070cba
6
+ metadata.gz: c889201fd88c6abbbb1cb77b4fc123dc1f49398dff060907f5ed1e9d9c79e6999fd2f94aebeb0a644fcfaeb9cebc094d67557791ded96b03ef358a05f5b4f086
7
+ data.tar.gz: 98d595503bd95bb1e477bd7ba47529f675e34d7d574e152276ba9c9147595c629cef76567819a763b0abe7659a5b873da0a6dd3706d5c3d89569eb40e9f43318
@@ -0,0 +1,129 @@
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
+ calculate_vm_cloud_properties
23
+ ).freeze
24
+
25
+ RPC_METHOD_TO_RUBY_METHOD = {
26
+ 'has_vm' => 'has_vm?',
27
+ 'has_disk' => 'has_disk?',
28
+ }.freeze
29
+
30
+ INVALID_CALL_ERROR_TYPE = 'InvalidCall'.freeze
31
+ UNKNOWN_ERROR_TYPE = 'Unknown'.freeze
32
+
33
+ def initialize(cpi, logs_string_io, result_io)
34
+ @cpi = cpi
35
+ @logs_string_io = logs_string_io
36
+ @result_io = result_io
37
+ end
38
+
39
+ def run(json)
40
+ begin
41
+ request = JSON.load(json)
42
+ rescue JSON::ParserError => e
43
+ return error_response(INVALID_CALL_ERROR_TYPE, "Request cannot be deserialized, details: #{e.message}", false, e.backtrace)
44
+ end
45
+
46
+ method = request['method']
47
+ unless method.is_a?(String)
48
+ return error_response(INVALID_CALL_ERROR_TYPE, "Method must be a String, got: '#{method.inspect}'", false)
49
+ end
50
+
51
+ unless KNOWN_RPC_METHODS.include?(method)
52
+ return error_response(INVALID_CALL_ERROR_TYPE, "Method is not known, got: '#{method}'", false)
53
+ end
54
+
55
+ arguments = request['arguments']
56
+ unless arguments.is_a?(Array)
57
+ return error_response(INVALID_CALL_ERROR_TYPE, "Arguments must be an Array, got: '#{arguments.inspect}'", false)
58
+ end
59
+
60
+ context = request['context']
61
+ unless context.is_a?(Hash) && context['director_uuid'].is_a?(String)
62
+ return error_response(INVALID_CALL_ERROR_TYPE, "Request should include context with director uuid, got: '#{context.inspect}'", false)
63
+ end
64
+
65
+ configure_director(context['director_uuid'])
66
+
67
+ ruby_method = RPC_METHOD_TO_RUBY_METHOD[method] || method
68
+
69
+ begin
70
+ cpi = @cpi.call(context)
71
+ result = cpi.public_send(ruby_method, *arguments)
72
+ rescue Bosh::Clouds::RetriableCloudError => e
73
+ return error_response(error_name(e), e.message, e.ok_to_retry, e.backtrace)
74
+ rescue Bosh::Clouds::CloudError, Bosh::Clouds::CpiError => e
75
+ return error_response(error_name(e), e.message, false, e.backtrace)
76
+ rescue ArgumentError => e
77
+ return error_response(INVALID_CALL_ERROR_TYPE, "Arguments are not correct, details: '#{e.message}'", false, e.backtrace)
78
+ rescue Exception => e
79
+ return error_response(UNKNOWN_ERROR_TYPE, e.message, false, e.backtrace)
80
+ end
81
+
82
+ result_response(result)
83
+ end
84
+
85
+ private
86
+
87
+ def configure_director(director_uuid)
88
+ Bosh::Clouds::Config.uuid = director_uuid
89
+ end
90
+
91
+ def error_response(type, message, ok_to_retry, bt=[])
92
+ if !bt.empty?
93
+ @logs_string_io.print("Rescued #{type}: #{message}. backtrace: #{bt.join("\n")}")
94
+ end
95
+
96
+ hash = {
97
+ result: nil,
98
+ error: {
99
+ type: type,
100
+ message: message,
101
+ ok_to_retry: ok_to_retry,
102
+ },
103
+ log: encode_string_as_utf8(@logs_string_io.string)
104
+ }
105
+ @result_io.print(JSON.dump(hash)); nil
106
+ end
107
+
108
+ def result_response(result)
109
+ hash = {
110
+ result: result,
111
+ error: nil,
112
+ log: encode_string_as_utf8(@logs_string_io.string)
113
+ }
114
+ @result_io.print(JSON.dump(hash)); nil
115
+ end
116
+
117
+ def error_name(error)
118
+ error.class.name
119
+ end
120
+
121
+ def encode_string_as_utf8(src)
122
+ log = @logs_string_io.string.force_encoding(Encoding::UTF_8)
123
+ unless log.valid_encoding?
124
+ # the src encoding hint of Encoding::BINARY is only required for ruby 1.9.3
125
+ log = @logs_string_io.string.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace, invalid: :replace)
126
+ end
127
+ log
128
+ end
129
+ 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,5 @@
1
+ require 'bosh/cpi'
2
+
3
+ module Bosh::Cpi
4
+ module CompatibilityHelpers; end
5
+ end
@@ -0,0 +1,106 @@
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
@@ -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
@@ -0,0 +1 @@
1
+ Dir.glob(File.expand_path('tasks/**/*.rake', File.dirname(__FILE__))).each { |r| import r }
data/lib/bosh/cpi.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Bosh
2
+ module Cpi; end
3
+ end
4
+
5
+ require 'bosh/cpi/cli'
6
+ require 'bosh/cpi/registry_client'
@@ -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,163 @@
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, properties_from_cpi_config = nil)
43
+ @cpi_path = cpi_path
44
+ @director_uuid = director_uuid
45
+ @logger = Config.logger
46
+ @properties_from_cpi_config = properties_from_cpi_config
47
+ end
48
+
49
+ def current_vm_id(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
50
+ def create_stemcell(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
51
+ def delete_stemcell(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
52
+ def create_vm(*arguments) invoke_cpi_method(__method__.to_s, *arguments); end
53
+ def delete_vm(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
54
+ def has_vm?(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
55
+ def reboot_vm(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
56
+ def set_vm_metadata(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
57
+ def create_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
58
+ def has_disk?(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
59
+ def delete_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
60
+ def attach_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
61
+ def detach_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
62
+ def snapshot_disk(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
63
+ def delete_snapshot(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
64
+ def get_disks(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
65
+ def ping(*arguments); invoke_cpi_method(__method__.to_s, *arguments); end
66
+
67
+ private
68
+
69
+ def invoke_cpi_method(method_name, *arguments)
70
+ context = {
71
+ 'director_uuid' => @director_uuid
72
+ }
73
+ context.merge!(@properties_from_cpi_config) unless @properties_from_cpi_config.nil?
74
+
75
+ request = request_json(method_name, arguments, context)
76
+ redacted_request = request_json(method_name, arguments, redact_context(context))
77
+
78
+ env = {'PATH' => '/usr/sbin:/usr/bin:/sbin:/bin', 'TMPDIR' => ENV['TMPDIR']}
79
+ cpi_exec_path = checked_cpi_exec_path
80
+
81
+ @logger.debug("External CPI sending request: #{redacted_request} with command: #{cpi_exec_path}")
82
+ cpi_response, stderr, exit_status = Open3.capture3(env, cpi_exec_path, stdin_data: request, unsetenv_others: true)
83
+ @logger.debug("External CPI got response: #{cpi_response}, err: #{stderr}, exit_status: #{exit_status}")
84
+
85
+ parsed_response = parsed_response(cpi_response)
86
+ validate_response(parsed_response)
87
+
88
+ if parsed_response['error']
89
+ handle_error(parsed_response['error'], method_name)
90
+ end
91
+
92
+ save_cpi_log(parsed_response['log'])
93
+ save_cpi_log(stderr)
94
+
95
+ parsed_response['result']
96
+ end
97
+
98
+ def checked_cpi_exec_path
99
+ unless File.executable?(@cpi_path)
100
+ raise NonExecutable, "Failed to run cpi: '#{@cpi_path}' is not executable"
101
+ end
102
+ @cpi_path
103
+ end
104
+
105
+ def redact_context(context)
106
+ return context if @properties_from_cpi_config.nil?
107
+ Hash[context.map{|k,v|[k,@properties_from_cpi_config.keys.include?(k) ? '<redacted>' : v]}]
108
+ end
109
+
110
+ def request_json(method_name, arguments, context)
111
+ JSON.dump({
112
+ 'method' => method_name.gsub(/\?$/,''),
113
+ 'arguments' => arguments,
114
+ 'context' => context
115
+ })
116
+ end
117
+
118
+ def handle_error(error_response, method_name)
119
+ error_type = error_response['type']
120
+ error_message = error_response['message']
121
+ unless KNOWN_RPC_ERRORS.include?(error_type)
122
+ raise UnknownError, "Unknown CPI error '#{error_type}' with message '#{error_message}' in '#{method_name}' CPI method"
123
+ end
124
+
125
+ error_class = constantize(error_type)
126
+
127
+ if error_class <= RetriableCloudError
128
+ error = error_class.new(error_response['ok_to_retry'])
129
+ else
130
+ error = error_class.new(error_message)
131
+ end
132
+
133
+ raise error, "CPI error '#{error_type}' with message '#{error_message}' in '#{method_name}' CPI method"
134
+ end
135
+
136
+ def save_cpi_log(output)
137
+ # cpi log path is set up at the beginning of every task in Config
138
+ # see JobRunner#setup_task_logging
139
+ File.open(Config.cpi_task_log, 'a') do |f|
140
+ f.write(output)
141
+ end
142
+ end
143
+
144
+ def parsed_response(input)
145
+ begin
146
+ JSON.load(input)
147
+ rescue JSON::ParserError => e
148
+ raise InvalidResponse, "Invalid CPI response - ParserError - #{e.message}"
149
+ end
150
+ end
151
+
152
+ def validate_response(response)
153
+ RESPONSE_SCHEMA.validate(response)
154
+ rescue Membrane::SchemaValidationError => e
155
+ raise InvalidResponse, "Invalid CPI response - SchemaValidationError: #{e.message}"
156
+ end
157
+
158
+ def constantize(camel_cased_word)
159
+ error_name = camel_cased_word.split('::').last
160
+ Bosh::Clouds.const_get(error_name)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,25 @@
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
@@ -0,0 +1,31 @@
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
@@ -0,0 +1,5 @@
1
+ module Bosh
2
+ module Clouds
3
+ VERSION = '2.0.1'
4
+ end
5
+ end
data/lib/cloud.rb ADDED
@@ -0,0 +1,229 @@
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
+ # Specify VM's hardware resources
214
+ # @param [Hash] vm_properties (typically cpu, ram, ephemeral_disk_size)
215
+ # @return [Hash] opaque description of the VM's configuration that
216
+ # can be used with {#create_vm}
217
+ def calculate_vm_cloud_properties(vm_properties)
218
+ not_implemented(:calculate_vm_cloud_properties)
219
+ end
220
+
221
+ private
222
+
223
+ def not_implemented(method)
224
+ raise Bosh::Clouds::NotImplemented,
225
+ "'#{method}' is not implemented by #{self.class}"
226
+ end
227
+
228
+ end
229
+ end
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: 2.0.0
4
+ version: 2.0.1
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-10 00:00:00.000000000 Z
11
+ date: 2016-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bosh_common
@@ -57,7 +57,21 @@ email: support@cloudfoundry.com
57
57
  executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
- files: []
60
+ files:
61
+ - lib/bosh/cpi.rb
62
+ - lib/bosh/cpi/cli.rb
63
+ - lib/bosh/cpi/compatibility_helpers.rb
64
+ - lib/bosh/cpi/compatibility_helpers/delete_vm.rb
65
+ - lib/bosh/cpi/registry_client.rb
66
+ - lib/bosh/cpi/tasks.rb
67
+ - lib/bosh/cpi/tasks/spec.rake
68
+ - lib/cloud.rb
69
+ - lib/cloud/config.rb
70
+ - lib/cloud/errors.rb
71
+ - lib/cloud/external_cpi.rb
72
+ - lib/cloud/internal_cpi.rb
73
+ - lib/cloud/provider.rb
74
+ - lib/cloud/version.rb
61
75
  homepage: https://github.com/cloudfoundry/bosh
62
76
  licenses:
63
77
  - Apache 2.0