chef-provisioning-fog 0.15.0 → 0.15.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 +4 -4
- data/Gemfile +11 -0
- data/LICENSE +201 -201
- data/README.md +208 -3
- data/Rakefile +6 -6
- data/chef-provisioning-fog.gemspec +28 -0
- data/lib/chef/provider/fog_key_pair.rb +266 -266
- data/lib/chef/provisioning/driver_init/fog.rb +3 -3
- data/lib/chef/provisioning/fog_driver/driver.rb +736 -736
- data/lib/chef/provisioning/fog_driver/providers/aws.rb +492 -492
- data/lib/chef/provisioning/fog_driver/providers/aws/credentials.rb +115 -115
- data/lib/chef/provisioning/fog_driver/providers/cloudstack.rb +44 -44
- data/lib/chef/provisioning/fog_driver/providers/digitalocean.rb +136 -136
- data/lib/chef/provisioning/fog_driver/providers/google.rb +85 -85
- data/lib/chef/provisioning/fog_driver/providers/joyent.rb +63 -63
- data/lib/chef/provisioning/fog_driver/providers/openstack.rb +117 -117
- data/lib/chef/provisioning/fog_driver/providers/rackspace.rb +42 -42
- data/lib/chef/provisioning/fog_driver/providers/softlayer.rb +36 -36
- data/lib/chef/provisioning/fog_driver/providers/vcair.rb +409 -409
- data/lib/chef/provisioning/fog_driver/providers/xenserver.rb +210 -210
- data/lib/chef/provisioning/fog_driver/recipe_dsl.rb +32 -32
- data/lib/chef/provisioning/fog_driver/version.rb +7 -7
- data/lib/chef/resource/fog_key_pair.rb +34 -34
- data/spec/spec_helper.rb +18 -18
- data/spec/support/aws/config-file.csv +2 -2
- data/spec/support/aws/ini-file.ini +10 -10
- data/spec/support/chef_metal_fog/providers/testdriver.rb +16 -16
- data/spec/unit/chef/provisioning/fog_driver/driver_spec.rb +71 -71
- data/spec/unit/fog_driver_spec.rb +32 -32
- data/spec/unit/providers/aws/credentials_spec.rb +45 -45
- data/spec/unit/providers/rackspace_spec.rb +16 -16
- metadata +5 -3
@@ -1,210 +1,210 @@
|
|
1
|
-
#fog:XenServer:<XenServer IP>
|
2
|
-
class Chef
|
3
|
-
module Provisioning
|
4
|
-
module FogDriver
|
5
|
-
module Providers
|
6
|
-
class XenServer < FogDriver::Driver
|
7
|
-
|
8
|
-
Driver.register_provider_class('XenServer', FogDriver::Providers::XenServer)
|
9
|
-
|
10
|
-
def creator
|
11
|
-
compute_options[:xenserver_username]
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.compute_options_for(provider, id, config)
|
15
|
-
new_compute_options = {}
|
16
|
-
new_compute_options[:provider] = provider
|
17
|
-
new_config = { driver_options: { compute_options: new_compute_options } }
|
18
|
-
new_defaults = {
|
19
|
-
driver_options: { compute_options: {} },
|
20
|
-
machine_options: { bootstrap_options: { affinity: id } }
|
21
|
-
}
|
22
|
-
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
23
|
-
|
24
|
-
new_compute_options[:xenserver_url] = id if id && id != ''
|
25
|
-
credential = Fog.credentials
|
26
|
-
|
27
|
-
new_compute_options[:xenserver_username] ||= credential[:xenserver_username]
|
28
|
-
new_compute_options[:xenserver_password] ||= credential[:xenserver_password]
|
29
|
-
new_compute_options[:xenserver_url] ||= credential[:xenserver_url]
|
30
|
-
new_compute_options[:xenserver_timeout] ||= 300
|
31
|
-
new_compute_options[:xenserver_redirect_to_master] ||= true
|
32
|
-
|
33
|
-
id = result[:driver_options][:compute_options][:xenserver_url]
|
34
|
-
|
35
|
-
[result, id]
|
36
|
-
end
|
37
|
-
|
38
|
-
def server_for(machine_spec)
|
39
|
-
if machine_spec.reference
|
40
|
-
compute.servers.get(compute.get_by_uuid(machine_spec.reference['server_id'], 'VM'))
|
41
|
-
else
|
42
|
-
nil
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def servers_for(machine_specs)
|
47
|
-
result = {}
|
48
|
-
machine_specs.each do |machine_spec|
|
49
|
-
if machine_spec.reference
|
50
|
-
if machine_spec.reference['driver_url'] != driver_url
|
51
|
-
raise "Switching a machine's driver from #{machine_spec.reference['driver_url']} to #{driver_url} for is not currently supported! Use machine :destroy and then re-create the machine on the new driver."
|
52
|
-
end
|
53
|
-
result[machine_spec] = compute.servers.get(compute.get_by_uuid(machine_spec.reference['server_id'], 'VM'))
|
54
|
-
else
|
55
|
-
result[machine_spec] = nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
result
|
59
|
-
end
|
60
|
-
|
61
|
-
def create_many_servers(num_servers, bootstrap_options, parallelizer)
|
62
|
-
parallelizer.parallelize(1.upto(num_servers)) do |i|
|
63
|
-
server = compute.servers.new(bootstrap_options)
|
64
|
-
server.save auto_start: false
|
65
|
-
|
66
|
-
if bootstrap_options[:affinity]
|
67
|
-
host = compute.hosts.all.select { |h| h.address == bootstrap_options[:affinity] }.first
|
68
|
-
if !host
|
69
|
-
raise "Host with ID #{bootstrap_options[:affinity]} not found."
|
70
|
-
end
|
71
|
-
server.set_attribute 'affinity', host.reference
|
72
|
-
end
|
73
|
-
|
74
|
-
unless bootstrap_options[:memory].nil?
|
75
|
-
mem = (bootstrap_options[:memory].to_i * 1024 * 1024).to_s
|
76
|
-
server.set_attribute 'memory_limits', mem, mem, mem, mem
|
77
|
-
end
|
78
|
-
|
79
|
-
unless bootstrap_options[:cpus].nil?
|
80
|
-
cpus = (bootstrap_options[:cpus]).to_s
|
81
|
-
server.set_attribute 'VCPUs_max', cpus
|
82
|
-
server.set_attribute 'VCPUs_at_startup', cpus
|
83
|
-
end
|
84
|
-
|
85
|
-
# network configuration through xenstore
|
86
|
-
attrs = {}
|
87
|
-
unless bootstrap_options[:network].nil?
|
88
|
-
network = bootstrap_options[:network]
|
89
|
-
attrs['vm-data/ip'] = network[:vm_ip] if network[:vm_ip]
|
90
|
-
attrs['vm-data/gw'] = network[:vm_gateway] if network[:vm_gateway]
|
91
|
-
attrs['vm-data/nm'] = network[:vm_netmask] if network[:vm_netmask]
|
92
|
-
attrs['vm-data/ns'] = network[:vm_dns] if network[:vm_dns]
|
93
|
-
attrs['vm-data/dm'] = network[:vm_domain] if network[:vm_domain]
|
94
|
-
if !attrs.empty?
|
95
|
-
server.set_attribute 'xenstore_data', attrs
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
server.provision
|
100
|
-
yield server if block_given?
|
101
|
-
server
|
102
|
-
end.to_a
|
103
|
-
end
|
104
|
-
|
105
|
-
def start_server(action_handler, machine_spec, server)
|
106
|
-
if server.state == 'Halted'
|
107
|
-
action_handler.perform_action "start machine #{machine_spec.name} (#{server.id} on #{driver_url})" do
|
108
|
-
server.start
|
109
|
-
machine_spec.reference['started_at'] = Time.now.to_i
|
110
|
-
end
|
111
|
-
machine_spec.save(action_handler)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def converge_floating_ips(action_handler, machine_spec, machine_options, server)
|
116
|
-
# XenServer does not have floating IPs
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
# Add methods required by the fog driver to XenServer's Server class
|
126
|
-
require 'fog/compute/models/server'
|
127
|
-
module Fog
|
128
|
-
module Compute
|
129
|
-
class XenServer
|
130
|
-
class Server < Fog::Compute::Server
|
131
|
-
def id
|
132
|
-
uuid
|
133
|
-
end
|
134
|
-
|
135
|
-
def state
|
136
|
-
attributes[:power_state]
|
137
|
-
end
|
138
|
-
|
139
|
-
def public_ip_address
|
140
|
-
if xenstore_data['vm-data/ip']
|
141
|
-
xenstore_data['vm-data/ip']
|
142
|
-
else
|
143
|
-
wait_for { tools_installed? }
|
144
|
-
if tools_installed?
|
145
|
-
guest_metrics.networks.first[1]
|
146
|
-
else
|
147
|
-
fail 'Unable to return IP address. Virtual machine does not ' \
|
148
|
-
'have XenTools installed or a timeout occurred.'
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def ready?
|
154
|
-
running?
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
#
|
162
|
-
# Use call_async instead of call on XMLPRPC::Client
|
163
|
-
# Otherwise machine_batch will fail since parallel calls will clash.
|
164
|
-
#
|
165
|
-
# See http://ruby-doc.org//stdlib-2.1.1//libdoc/xmlrpc/rdoc/XMLRPC/Client.html
|
166
|
-
#
|
167
|
-
module Fog
|
168
|
-
module XenServer
|
169
|
-
class Connection
|
170
|
-
require 'xmlrpc/client'
|
171
|
-
attr_reader :credentials
|
172
|
-
|
173
|
-
def request(options, *params)
|
174
|
-
begin
|
175
|
-
parser = options.delete(:parser)
|
176
|
-
method = options.delete(:method)
|
177
|
-
|
178
|
-
if params.empty?
|
179
|
-
response = @factory.call_async(method, @credentials)
|
180
|
-
else
|
181
|
-
if params.length.eql?(1) and params.first.is_a?(Hash)
|
182
|
-
response = @factory.call_async(method, @credentials, params.first)
|
183
|
-
elsif params.length.eql?(2) and params.last.is_a?(Array)
|
184
|
-
response = @factory.call_async(method, @credentials, params.first, params.last)
|
185
|
-
else
|
186
|
-
response = eval("@factory.call_async('#{method}', '#{@credentials}', #{params.map { |p| p.is_a?(String) ? "'#{p}'" : p }.join(',')})")
|
187
|
-
end
|
188
|
-
end
|
189
|
-
raise RequestFailed.new("#{method}: " + response["ErrorDescription"].to_s) unless response["Status"].eql? "Success"
|
190
|
-
if parser
|
191
|
-
parser.parse(response["Value"])
|
192
|
-
response = parser.response
|
193
|
-
end
|
194
|
-
|
195
|
-
response
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
module Fog
|
204
|
-
class Logger
|
205
|
-
def self.deprecation(message)
|
206
|
-
# Silence...ahh
|
207
|
-
Chef::Log.debug('Fog: ' + message)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
1
|
+
#fog:XenServer:<XenServer IP>
|
2
|
+
class Chef
|
3
|
+
module Provisioning
|
4
|
+
module FogDriver
|
5
|
+
module Providers
|
6
|
+
class XenServer < FogDriver::Driver
|
7
|
+
|
8
|
+
Driver.register_provider_class('XenServer', FogDriver::Providers::XenServer)
|
9
|
+
|
10
|
+
def creator
|
11
|
+
compute_options[:xenserver_username]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.compute_options_for(provider, id, config)
|
15
|
+
new_compute_options = {}
|
16
|
+
new_compute_options[:provider] = provider
|
17
|
+
new_config = { driver_options: { compute_options: new_compute_options } }
|
18
|
+
new_defaults = {
|
19
|
+
driver_options: { compute_options: {} },
|
20
|
+
machine_options: { bootstrap_options: { affinity: id } }
|
21
|
+
}
|
22
|
+
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
23
|
+
|
24
|
+
new_compute_options[:xenserver_url] = id if id && id != ''
|
25
|
+
credential = Fog.credentials
|
26
|
+
|
27
|
+
new_compute_options[:xenserver_username] ||= credential[:xenserver_username]
|
28
|
+
new_compute_options[:xenserver_password] ||= credential[:xenserver_password]
|
29
|
+
new_compute_options[:xenserver_url] ||= credential[:xenserver_url]
|
30
|
+
new_compute_options[:xenserver_timeout] ||= 300
|
31
|
+
new_compute_options[:xenserver_redirect_to_master] ||= true
|
32
|
+
|
33
|
+
id = result[:driver_options][:compute_options][:xenserver_url]
|
34
|
+
|
35
|
+
[result, id]
|
36
|
+
end
|
37
|
+
|
38
|
+
def server_for(machine_spec)
|
39
|
+
if machine_spec.reference
|
40
|
+
compute.servers.get(compute.get_by_uuid(machine_spec.reference['server_id'], 'VM'))
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def servers_for(machine_specs)
|
47
|
+
result = {}
|
48
|
+
machine_specs.each do |machine_spec|
|
49
|
+
if machine_spec.reference
|
50
|
+
if machine_spec.reference['driver_url'] != driver_url
|
51
|
+
raise "Switching a machine's driver from #{machine_spec.reference['driver_url']} to #{driver_url} for is not currently supported! Use machine :destroy and then re-create the machine on the new driver."
|
52
|
+
end
|
53
|
+
result[machine_spec] = compute.servers.get(compute.get_by_uuid(machine_spec.reference['server_id'], 'VM'))
|
54
|
+
else
|
55
|
+
result[machine_spec] = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_many_servers(num_servers, bootstrap_options, parallelizer)
|
62
|
+
parallelizer.parallelize(1.upto(num_servers)) do |i|
|
63
|
+
server = compute.servers.new(bootstrap_options)
|
64
|
+
server.save auto_start: false
|
65
|
+
|
66
|
+
if bootstrap_options[:affinity]
|
67
|
+
host = compute.hosts.all.select { |h| h.address == bootstrap_options[:affinity] }.first
|
68
|
+
if !host
|
69
|
+
raise "Host with ID #{bootstrap_options[:affinity]} not found."
|
70
|
+
end
|
71
|
+
server.set_attribute 'affinity', host.reference
|
72
|
+
end
|
73
|
+
|
74
|
+
unless bootstrap_options[:memory].nil?
|
75
|
+
mem = (bootstrap_options[:memory].to_i * 1024 * 1024).to_s
|
76
|
+
server.set_attribute 'memory_limits', mem, mem, mem, mem
|
77
|
+
end
|
78
|
+
|
79
|
+
unless bootstrap_options[:cpus].nil?
|
80
|
+
cpus = (bootstrap_options[:cpus]).to_s
|
81
|
+
server.set_attribute 'VCPUs_max', cpus
|
82
|
+
server.set_attribute 'VCPUs_at_startup', cpus
|
83
|
+
end
|
84
|
+
|
85
|
+
# network configuration through xenstore
|
86
|
+
attrs = {}
|
87
|
+
unless bootstrap_options[:network].nil?
|
88
|
+
network = bootstrap_options[:network]
|
89
|
+
attrs['vm-data/ip'] = network[:vm_ip] if network[:vm_ip]
|
90
|
+
attrs['vm-data/gw'] = network[:vm_gateway] if network[:vm_gateway]
|
91
|
+
attrs['vm-data/nm'] = network[:vm_netmask] if network[:vm_netmask]
|
92
|
+
attrs['vm-data/ns'] = network[:vm_dns] if network[:vm_dns]
|
93
|
+
attrs['vm-data/dm'] = network[:vm_domain] if network[:vm_domain]
|
94
|
+
if !attrs.empty?
|
95
|
+
server.set_attribute 'xenstore_data', attrs
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
server.provision
|
100
|
+
yield server if block_given?
|
101
|
+
server
|
102
|
+
end.to_a
|
103
|
+
end
|
104
|
+
|
105
|
+
def start_server(action_handler, machine_spec, server)
|
106
|
+
if server.state == 'Halted'
|
107
|
+
action_handler.perform_action "start machine #{machine_spec.name} (#{server.id} on #{driver_url})" do
|
108
|
+
server.start
|
109
|
+
machine_spec.reference['started_at'] = Time.now.to_i
|
110
|
+
end
|
111
|
+
machine_spec.save(action_handler)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def converge_floating_ips(action_handler, machine_spec, machine_options, server)
|
116
|
+
# XenServer does not have floating IPs
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# Add methods required by the fog driver to XenServer's Server class
|
126
|
+
require 'fog/compute/models/server'
|
127
|
+
module Fog
|
128
|
+
module Compute
|
129
|
+
class XenServer
|
130
|
+
class Server < Fog::Compute::Server
|
131
|
+
def id
|
132
|
+
uuid
|
133
|
+
end
|
134
|
+
|
135
|
+
def state
|
136
|
+
attributes[:power_state]
|
137
|
+
end
|
138
|
+
|
139
|
+
def public_ip_address
|
140
|
+
if xenstore_data['vm-data/ip']
|
141
|
+
xenstore_data['vm-data/ip']
|
142
|
+
else
|
143
|
+
wait_for { tools_installed? }
|
144
|
+
if tools_installed?
|
145
|
+
guest_metrics.networks.first[1]
|
146
|
+
else
|
147
|
+
fail 'Unable to return IP address. Virtual machine does not ' \
|
148
|
+
'have XenTools installed or a timeout occurred.'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def ready?
|
154
|
+
running?
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Use call_async instead of call on XMLPRPC::Client
|
163
|
+
# Otherwise machine_batch will fail since parallel calls will clash.
|
164
|
+
#
|
165
|
+
# See http://ruby-doc.org//stdlib-2.1.1//libdoc/xmlrpc/rdoc/XMLRPC/Client.html
|
166
|
+
#
|
167
|
+
module Fog
|
168
|
+
module XenServer
|
169
|
+
class Connection
|
170
|
+
require 'xmlrpc/client'
|
171
|
+
attr_reader :credentials
|
172
|
+
|
173
|
+
def request(options, *params)
|
174
|
+
begin
|
175
|
+
parser = options.delete(:parser)
|
176
|
+
method = options.delete(:method)
|
177
|
+
|
178
|
+
if params.empty?
|
179
|
+
response = @factory.call_async(method, @credentials)
|
180
|
+
else
|
181
|
+
if params.length.eql?(1) and params.first.is_a?(Hash)
|
182
|
+
response = @factory.call_async(method, @credentials, params.first)
|
183
|
+
elsif params.length.eql?(2) and params.last.is_a?(Array)
|
184
|
+
response = @factory.call_async(method, @credentials, params.first, params.last)
|
185
|
+
else
|
186
|
+
response = eval("@factory.call_async('#{method}', '#{@credentials}', #{params.map { |p| p.is_a?(String) ? "'#{p}'" : p }.join(',')})")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
raise RequestFailed.new("#{method}: " + response["ErrorDescription"].to_s) unless response["Status"].eql? "Success"
|
190
|
+
if parser
|
191
|
+
parser.parse(response["Value"])
|
192
|
+
response = parser.response
|
193
|
+
end
|
194
|
+
|
195
|
+
response
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
module Fog
|
204
|
+
class Logger
|
205
|
+
def self.deprecation(message)
|
206
|
+
# Silence...ahh
|
207
|
+
Chef::Log.debug('Fog: ' + message)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -1,32 +1,32 @@
|
|
1
|
-
require 'chef/provisioning/fog_driver/driver'
|
2
|
-
require 'chef/resource/fog_key_pair'
|
3
|
-
require 'chef/provider/fog_key_pair'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
module DSL
|
7
|
-
module Recipe
|
8
|
-
def with_fog_driver(provider, driver_options = nil, &block)
|
9
|
-
config = Cheffish::MergedConfig.new({ :driver_options => driver_options }, run_context.config)
|
10
|
-
driver = Driver.from_provider(provider, config)
|
11
|
-
run_context.chef_provisioning.with_driver(driver, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def with_fog_ec2_driver(driver_options = nil, &block)
|
15
|
-
with_fog_driver('AWS', driver_options, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def with_fog_openstack_driver(driver_options = nil, &block)
|
19
|
-
with_fog_driver('OpenStack', driver_options, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
def with_fog_rackspace_driver(driver_options = nil, &block)
|
23
|
-
with_fog_driver('Rackspace', driver_options, &block)
|
24
|
-
end
|
25
|
-
|
26
|
-
def with_fog_vcair_driver(driver_options = nil, &block)
|
27
|
-
with_fog_driver('Vcair', driver_options, &block)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
1
|
+
require 'chef/provisioning/fog_driver/driver'
|
2
|
+
require 'chef/resource/fog_key_pair'
|
3
|
+
require 'chef/provider/fog_key_pair'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module DSL
|
7
|
+
module Recipe
|
8
|
+
def with_fog_driver(provider, driver_options = nil, &block)
|
9
|
+
config = Cheffish::MergedConfig.new({ :driver_options => driver_options }, run_context.config)
|
10
|
+
driver = Driver.from_provider(provider, config)
|
11
|
+
run_context.chef_provisioning.with_driver(driver, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_fog_ec2_driver(driver_options = nil, &block)
|
15
|
+
with_fog_driver('AWS', driver_options, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_fog_openstack_driver(driver_options = nil, &block)
|
19
|
+
with_fog_driver('OpenStack', driver_options, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_fog_rackspace_driver(driver_options = nil, &block)
|
23
|
+
with_fog_driver('Rackspace', driver_options, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def with_fog_vcair_driver(driver_options = nil, &block)
|
27
|
+
with_fog_driver('Vcair', driver_options, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|