dopv 0.11.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 +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/ChangeLog.md +456 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +260 -0
- data/Guardfile +22 -0
- data/LICENSE.txt +177 -0
- data/README.md +214 -0
- data/Rakefile +6 -0
- data/bin/dopv +4 -0
- data/dopv.gemspec +52 -0
- data/lib/dopv.rb +166 -0
- data/lib/dopv/cli.rb +54 -0
- data/lib/dopv/cli/command_add.rb +37 -0
- data/lib/dopv/cli/command_export.rb +26 -0
- data/lib/dopv/cli/command_import.rb +32 -0
- data/lib/dopv/cli/command_list.rb +18 -0
- data/lib/dopv/cli/command_remove.rb +29 -0
- data/lib/dopv/cli/command_run.rb +38 -0
- data/lib/dopv/cli/command_update.rb +35 -0
- data/lib/dopv/cli/command_validate.rb +30 -0
- data/lib/dopv/infrastructure.rb +40 -0
- data/lib/dopv/infrastructure/providers/baremetal.rb +12 -0
- data/lib/dopv/infrastructure/providers/base.rb +422 -0
- data/lib/dopv/infrastructure/providers/openstack.rb +308 -0
- data/lib/dopv/infrastructure/providers/ovirt.rb +228 -0
- data/lib/dopv/infrastructure/providers/vsphere.rb +322 -0
- data/lib/dopv/log.rb +14 -0
- data/lib/dopv/persistent_disk.rb +128 -0
- data/lib/dopv/plan.rb +17 -0
- data/lib/dopv/state_store.rb +87 -0
- data/lib/dopv/version.rb +3 -0
- data/spec/data/hooks/test_hook_script_1 +9 -0
- data/spec/data/hooks/test_hook_script_2 +10 -0
- data/spec/data/plans/test-plan-1.yaml +140 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/unit/dopv/dopv_spec.rb +7 -0
- data/spec/unit/dopv/persistent_disk_spec.rb +38 -0
- data/spec/unit/dopv/plan_spec.rb +34 -0
- data/spec/unit/dopv/version_spec.rb +17 -0
- metadata +401 -0
@@ -0,0 +1,308 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Dopv
|
4
|
+
module Infrastructure
|
5
|
+
class OpenStack < Base
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegator :@plan, :flavor, :flavor_name
|
9
|
+
|
10
|
+
def initialize(node_config, data_disks_db)
|
11
|
+
super(node_config, data_disks_db)
|
12
|
+
|
13
|
+
|
14
|
+
@compute_connection_opts = {
|
15
|
+
:provider => 'openstack',
|
16
|
+
:openstack_username => provider_username,
|
17
|
+
:openstack_api_key => provider_password,
|
18
|
+
:openstack_project_name => provider_tenant,
|
19
|
+
:openstack_domain_id => provider_domain_id,
|
20
|
+
:openstack_auth_url => provider_url,
|
21
|
+
:openstack_endpoint_type => provider_endpoint_type,
|
22
|
+
:connection_options => {
|
23
|
+
:ssl_verify_peer => false,
|
24
|
+
#:debug_request => true
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
@network_connection_opts = @compute_connection_opts
|
29
|
+
@volume_connection_opts = @compute_connection_opts
|
30
|
+
|
31
|
+
@node_creation_opts = {
|
32
|
+
:name => nodename,
|
33
|
+
:image_ref => template.id,
|
34
|
+
:flavor_ref => flavor.id,
|
35
|
+
:config_drive => use_config_drive?,
|
36
|
+
:security_groups => security_groups
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def provider_tenant
|
43
|
+
@provider_tenant ||= infrastructure_properties.tenant
|
44
|
+
end
|
45
|
+
|
46
|
+
def provider_domain_id
|
47
|
+
@provider_domain_id ||= infrastructure_properties.domain_id
|
48
|
+
end
|
49
|
+
|
50
|
+
def provider_endpoint_type
|
51
|
+
@provider_endpoint_type ||= infrastructure_properties.endpoint_type
|
52
|
+
end
|
53
|
+
|
54
|
+
def use_config_drive?
|
55
|
+
@use_config_drive ||= infrastructure_properties.use_config_drive?
|
56
|
+
end
|
57
|
+
|
58
|
+
def security_groups
|
59
|
+
@security_groups ||= infrastructure_properties.security_groups
|
60
|
+
end
|
61
|
+
|
62
|
+
def network_provider
|
63
|
+
Dopv::log.info("Node #{nodename}: Creating network provider.") unless @network_provider
|
64
|
+
@network_provider ||= @network_connection_opts ? ::Fog::Network.new(@network_connection_opts) : nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def flavor(filters={})
|
68
|
+
@flavor ||= compute_provider.flavors(filters).find { |f| f.name == flavor_name }
|
69
|
+
raise ProviderError, "No such flavor #{flavor_name}" unless @flavor
|
70
|
+
@flavor
|
71
|
+
end
|
72
|
+
|
73
|
+
def network(name, filters={})
|
74
|
+
net = network_provider.networks(filters).find { |n| n.name == name || n.id == name }
|
75
|
+
raise ProviderError, "No such network #{name}" unless net
|
76
|
+
net
|
77
|
+
end
|
78
|
+
|
79
|
+
def subnet(name, filters={})
|
80
|
+
net = network_provider.subnets(filters).find { |s| s.name == name || s.id == name }
|
81
|
+
raise ProviderError, "No such subnetwork #{name}" unless net
|
82
|
+
net
|
83
|
+
end
|
84
|
+
|
85
|
+
def assign_security_groups(node_instance)
|
86
|
+
unless security_groups.empty?
|
87
|
+
Dopv::log.info("Node #{nodename}: Assigning security groups.")
|
88
|
+
config_sgs = security_groups.dup
|
89
|
+
node_instance.security_groups.uniq { |g| g.id }.each do |sg|
|
90
|
+
# Remove the security group from configuration if it is already
|
91
|
+
# assigned to an instance.
|
92
|
+
if config_sgs.delete(sg.name)
|
93
|
+
Dopv::log.debug("Node #{nodename}: Already assigned to security group #{sg.name}.")
|
94
|
+
next
|
95
|
+
end
|
96
|
+
# Remove the security group assignment if it isn't in the
|
97
|
+
# configuration.
|
98
|
+
unless config_sgs.include?(sg.name)
|
99
|
+
Dopv::log.debug("Node #{nodename}: Removing unneeded security group #{sg.name}.")
|
100
|
+
compute_provider.remove_security_group(node_instance.id, sg.name)
|
101
|
+
wait_for_task_completion(node_instance)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
# Add remaining security groups defined in config array.
|
105
|
+
config_sgs.each do |sg_name|
|
106
|
+
begin
|
107
|
+
Dopv::log.debug("Node #{nodename}: Adding security group #{sg_name}.")
|
108
|
+
compute_provider.add_security_group(node_instance.id, sg_name)
|
109
|
+
wait_for_task_completion(node_instance)
|
110
|
+
rescue
|
111
|
+
raise ProviderError, "An error occured while assigning security group #{sg_name}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
node_instance.reload
|
115
|
+
end
|
116
|
+
node_instance.security_groups
|
117
|
+
end
|
118
|
+
|
119
|
+
def node_instance_stopped?(node_instance)
|
120
|
+
!node_instance.ready?
|
121
|
+
end
|
122
|
+
|
123
|
+
def wait_for_task_completion(node_instance)
|
124
|
+
node_instance.wait_for { ready? }
|
125
|
+
end
|
126
|
+
|
127
|
+
def create_node_instance
|
128
|
+
Dopv::log.info("Node #{nodename}: Creating node instance.")
|
129
|
+
|
130
|
+
@node_creation_opts[:nics] = add_node_network_ports
|
131
|
+
@node_creation_opts[:user_data_encoded] = [cloud_config].pack('m')
|
132
|
+
|
133
|
+
Dopv::log.debug("Node #{nodename}: Spawning node instance.")
|
134
|
+
instance = compute_provider.servers.create(@node_creation_opts)
|
135
|
+
wait_for_task_completion(instance)
|
136
|
+
instance.reload
|
137
|
+
|
138
|
+
assign_security_groups(instance)
|
139
|
+
|
140
|
+
instance
|
141
|
+
end
|
142
|
+
|
143
|
+
def destroy_node_instance(node_instance, destroy_data_volumes=false)
|
144
|
+
remove_node_floating_ips(node_instance)
|
145
|
+
remove_node_network_ports(node_instance)
|
146
|
+
super(node_instance, destroy_data_volumes)
|
147
|
+
end
|
148
|
+
|
149
|
+
def start_node_instance(node_instance)
|
150
|
+
end
|
151
|
+
|
152
|
+
def stop_node_instance(node_instance)
|
153
|
+
super(node_instance)
|
154
|
+
node_instance.wait_for { !ready? }
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_node_volume(node_instance, config)
|
158
|
+
volume = super(
|
159
|
+
compute_provider, {
|
160
|
+
:name => config.name,
|
161
|
+
:display_name => config.name,
|
162
|
+
:size => config.size.gibibytes.to_i,
|
163
|
+
:volume_type => config.pool,
|
164
|
+
:description => config.name
|
165
|
+
}
|
166
|
+
)
|
167
|
+
volume.wait_for { ready? }
|
168
|
+
attach_node_volume(node_instance, volume.reload)
|
169
|
+
volume.reload
|
170
|
+
end
|
171
|
+
|
172
|
+
def destroy_node_volume(node_instance, volume)
|
173
|
+
volume_instance = detach_node_volume(node_instance, volume)
|
174
|
+
volume_instance.destroy
|
175
|
+
node_instance.volumes.all({}).reload
|
176
|
+
end
|
177
|
+
|
178
|
+
def attach_node_volume(node_instance, volume)
|
179
|
+
volume_instance = node_instance.volumes.all({}).find { |v| v.id = volume.id }
|
180
|
+
node_instance.attach_volume(volume_instance.id, nil)
|
181
|
+
volume_instance.wait_for { volume_instance.status.downcase == "in-use" }
|
182
|
+
volume_instance
|
183
|
+
end
|
184
|
+
|
185
|
+
def detach_node_volume(node_instance, volume)
|
186
|
+
volume_instance = node_instance.volumes.all({}).find { |v| v.id = volume.id }
|
187
|
+
node_instance.detach_volume(volume_instance.id)
|
188
|
+
volume_instance.wait_for { volume_instance.status.downcase == "available" }
|
189
|
+
volume_instance
|
190
|
+
end
|
191
|
+
|
192
|
+
def record_node_data_volume(volume)
|
193
|
+
super(
|
194
|
+
:name => volume.name,
|
195
|
+
:id => volume.id,
|
196
|
+
:pool => volume.type == 'None' ? nil : volume.type,
|
197
|
+
:size => volume.size * 1073741824 # Returned in gibibytes
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
def fixed_ip(subnet_id, ip_address)
|
202
|
+
rval = { :subnet_id => subnet_id }
|
203
|
+
[:dhcp, :none].include?(ip_address) ? rval : rval.merge(:ip_address => ip_address)
|
204
|
+
end
|
205
|
+
|
206
|
+
def add_node_network_port(attrs)
|
207
|
+
::Dopv::log.debug("Node #{nodename}: Adding network port #{attrs[:name]}.")
|
208
|
+
network_provider.ports.create(attrs)
|
209
|
+
end
|
210
|
+
|
211
|
+
def add_node_network_ports
|
212
|
+
::Dopv::log.info("Node #{nodename}: Adding network ports.")
|
213
|
+
ports_config = {}
|
214
|
+
interfaces_config.each do |i|
|
215
|
+
s = subnet(i.network)
|
216
|
+
port_name = "#{nodename}_#{s.network_id}"
|
217
|
+
if ports_config.has_key?(port_name)
|
218
|
+
ports_config[port_name][:fixed_ips] << fixed_ip(s.id, i.ip)
|
219
|
+
else
|
220
|
+
ports_config[port_name] = {
|
221
|
+
:network_id => s.network_id,
|
222
|
+
:fixed_ips => [fixed_ip(s.id, i.ip)]
|
223
|
+
}
|
224
|
+
end
|
225
|
+
end
|
226
|
+
@network_ports = ports_config.map { |k,v| add_node_network_port(v.merge(:name => k)) }
|
227
|
+
@network_ports.collect { |p| {:net_id => p.network_id, :port_id => p.id} } # Net ID is required in Liberty++
|
228
|
+
end
|
229
|
+
|
230
|
+
def remove_node_network_ports(node_instance)
|
231
|
+
::Dopv::log.warn("Node #{nodename}: Removing network ports.")
|
232
|
+
@network_ports ||= network_provider.ports.select { |p| p.device_id == node_instance.id } rescue {}
|
233
|
+
@network_ports.each { |p| p.destroy rescue nil } # TODO: dangerous, rewrite
|
234
|
+
@network_ports = {}
|
235
|
+
end
|
236
|
+
|
237
|
+
def add_node_floating_ip(attrs)
|
238
|
+
::Dopv::log.debug("Node #{nodename}: Adding floating IP to #{attrs[:nicname]}.")
|
239
|
+
network_provider.floating_ips.create(attrs)
|
240
|
+
end
|
241
|
+
|
242
|
+
def add_node_floating_ips(node_instance)
|
243
|
+
::Dopv::log.info("Node #{nodename}: Adding floating IPs.")
|
244
|
+
@network_ports ||= network_provider.ports.select { |p| p.device_id == node_instance.id }
|
245
|
+
interfaces_config.each do |i|
|
246
|
+
if i.floating_network
|
247
|
+
floating_network = network(i.floating_network)
|
248
|
+
subnetwork = subnet(i.network)
|
249
|
+
port = @network_ports.find { |p| p.fixed_ips.find { |f| f["subnet_id"] == subnetwork.id } }
|
250
|
+
attrs = {
|
251
|
+
:floating_network_id => floating_network.id,
|
252
|
+
:port_id => port.id,
|
253
|
+
:fixed_ip_address => port.fixed_ips.first["ip_address"],
|
254
|
+
:nicname => i.name
|
255
|
+
}
|
256
|
+
add_node_floating_ip(attrs)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
alias_method :add_node_nics, :add_node_floating_ips
|
261
|
+
|
262
|
+
def remove_node_floating_ips(node_instance)
|
263
|
+
::Dopv::log.warn("Node #{nodename}: Removing floating IPs.")
|
264
|
+
if node_instance
|
265
|
+
floating_ips = network_provider.floating_ips.select do |f|
|
266
|
+
node_instance.floating_ip_addresses.include?(f.floating_ip_address)
|
267
|
+
end
|
268
|
+
floating_ips.each { |f| f.destroy rescue nil } # TODO: dangerous, rewrite
|
269
|
+
end
|
270
|
+
end
|
271
|
+
alias_method :remove_node_nics, :remove_node_floating_ips
|
272
|
+
|
273
|
+
def cloud_config
|
274
|
+
config = "#cloud-config\n" \
|
275
|
+
"hostname: #{hostname}\n" \
|
276
|
+
"fqdn: #{fqdn}\n" \
|
277
|
+
"manage_etc_hosts: True\n" \
|
278
|
+
"ssh_pwauth: True\n"
|
279
|
+
|
280
|
+
if root_password
|
281
|
+
config << \
|
282
|
+
"chpasswd:\n" \
|
283
|
+
" list: |\n" \
|
284
|
+
" root:#{root_password}\n" \
|
285
|
+
" expire: False\n"
|
286
|
+
end
|
287
|
+
|
288
|
+
unless root_ssh_pubkeys.empty?
|
289
|
+
config << \
|
290
|
+
"users:\n" \
|
291
|
+
" - name: root\n" \
|
292
|
+
" ssh_authorized_keys:\n"
|
293
|
+
root_ssh_pubkeys.each { |k| config << " - #{k}\n" }
|
294
|
+
end
|
295
|
+
|
296
|
+
config <<
|
297
|
+
"runcmd:\n" \
|
298
|
+
" - service network restart\n"
|
299
|
+
|
300
|
+
config
|
301
|
+
end
|
302
|
+
|
303
|
+
def get_node_ip_addresses(node_instance)
|
304
|
+
(node_instance.ip_addresses + [node_instance.floating_ip_address]).flatten.uniq.compact
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'fog'
|
2
|
+
require 'uri'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module Dopv
|
6
|
+
module Infrastructure
|
7
|
+
class Ovirt < Base
|
8
|
+
def initialize(plan, data_disks_db)
|
9
|
+
super(plan, data_disks_db)
|
10
|
+
|
11
|
+
@compute_connection_opts = {
|
12
|
+
:provider => 'ovirt',
|
13
|
+
:ovirt_username => provider_username,
|
14
|
+
:ovirt_password => provider_password,
|
15
|
+
:ovirt_url => provider_url,
|
16
|
+
:ovirt_ca_cert_file => provider_ca_cert_file
|
17
|
+
}
|
18
|
+
|
19
|
+
@node_creation_opts = {
|
20
|
+
:name => nodename,
|
21
|
+
:template => template.id,
|
22
|
+
:cores => cores,
|
23
|
+
:memory => memory.bytes,
|
24
|
+
:storage => storage.bytes,
|
25
|
+
:cluster => cluster.id,
|
26
|
+
:ha => keep_ha?,
|
27
|
+
:clone => full_clone?,
|
28
|
+
:storagedomain_name => infrastructure_properties.default_pool
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def compute_provider
|
35
|
+
unless @compute_provider
|
36
|
+
super
|
37
|
+
::Dopv::log.debug("Node #{nodename}: Recreating client with proper datacenter.")
|
38
|
+
@compute_connection_opts[:ovirt_datacenter] = datacenter[:id]
|
39
|
+
@compute_provider = ::Fog::Compute.new(@compute_connection_opts)
|
40
|
+
end
|
41
|
+
@compute_provider
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_node_instance
|
45
|
+
super({:without_details => true})
|
46
|
+
end
|
47
|
+
|
48
|
+
def wait_for_task_completion(node_instance)
|
49
|
+
node_instance.wait_for { !locked? }
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_node_instance
|
53
|
+
node_instance = super
|
54
|
+
|
55
|
+
# For each disk, set up wipe after delete flag
|
56
|
+
node_instance.volumes.each do |v|
|
57
|
+
::Dopv::log.debug("Node #{nodename}: Setting wipe after delete for disk #{v.alias}.")
|
58
|
+
update_node_volume(node_instance, v, {:wipe_after_delete => true})
|
59
|
+
end
|
60
|
+
|
61
|
+
node_instance
|
62
|
+
end
|
63
|
+
|
64
|
+
def customize_node_instance(node_instance)
|
65
|
+
::Dopv::log.info("Node #{nodename}: Customizing node.")
|
66
|
+
customization_opts = {
|
67
|
+
:hostname => fqdn,
|
68
|
+
:dns => dns.name_servers,
|
69
|
+
:domain => dns.search_domains,
|
70
|
+
:user => 'root',
|
71
|
+
:password => root_password,
|
72
|
+
:ssh_authorized_keys => root_ssh_pubkeys
|
73
|
+
}
|
74
|
+
|
75
|
+
customization_opts[:nicsdef] = interfaces_config.collect do |i|
|
76
|
+
nic = {}
|
77
|
+
nic[:nicname] = i.name
|
78
|
+
nic[:on_boot] = 'true'
|
79
|
+
nic[:boot_protocol] = case i.ip
|
80
|
+
when :dhcp
|
81
|
+
'DHCP'
|
82
|
+
when :none
|
83
|
+
'NONE'
|
84
|
+
else
|
85
|
+
'STATIC'
|
86
|
+
end
|
87
|
+
unless [:dhcp, :none].include?(i.ip)
|
88
|
+
nic[:ip] = i.ip
|
89
|
+
nic[:netmask] = i.netmask
|
90
|
+
nic[:gateway] = i.gateway if i.set_gateway?
|
91
|
+
end
|
92
|
+
nic
|
93
|
+
end
|
94
|
+
|
95
|
+
customization_opts
|
96
|
+
end
|
97
|
+
|
98
|
+
def start_node_instance(node_instance)
|
99
|
+
customization_opts = super(node_instance)
|
100
|
+
node_instance.service.vm_start_with_cloudinit(
|
101
|
+
:id => node_instance.id,
|
102
|
+
:user_data => customization_opts
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Redefine until regexp in Fog::Compute::Ovirt::Server#stopped? is fixed
|
107
|
+
def stop_node_instance(node_instance)
|
108
|
+
super
|
109
|
+
node_instance.wait_for { status.downcase == 'down' }
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_node_nic(node_instance, attrs)
|
113
|
+
nic = node_instance.add_interface(attrs)
|
114
|
+
node_instance.interfaces.reload
|
115
|
+
nic
|
116
|
+
end
|
117
|
+
|
118
|
+
def update_node_nic(node_instance, nic, attrs)
|
119
|
+
node_instance.update_interface(attrs.merge({:id => nic.id}))
|
120
|
+
node_instance.interfaces.reload
|
121
|
+
end
|
122
|
+
|
123
|
+
def add_node_nics(node_instance)
|
124
|
+
::Dopv::log.info("Node #{nodename}: Trying to add interfaces.")
|
125
|
+
|
126
|
+
# Remove all interfaces defined by the template
|
127
|
+
remove_node_nics(node_instance) { |n, i| n.destroy_interface(:id => i.id) }
|
128
|
+
|
129
|
+
# fetch first network for our reservation dance
|
130
|
+
first_network = cluster.networks.first.name
|
131
|
+
# Reserve MAC addresses
|
132
|
+
(1..interfaces_config.size).each do |i|
|
133
|
+
name = "tmp#{i}"
|
134
|
+
::Dopv::log.debug("Node #{nodename}: Creating interface #{name}.")
|
135
|
+
attrs = {
|
136
|
+
:name => name,
|
137
|
+
:network_name => first_network,
|
138
|
+
:plugged => true,
|
139
|
+
:linked => true
|
140
|
+
}
|
141
|
+
add_node_nic(node_instance, attrs)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Rearrange interfaces by their MAC addresses and assign them into
|
145
|
+
# appropriate networks
|
146
|
+
ic = interfaces_config.reverse
|
147
|
+
node_instance.interfaces.sort_by do |n| n.mac
|
148
|
+
i = ic.pop
|
149
|
+
::Dopv::log.debug("Node #{nodename}: Configuring interface #{n.name} (#{n.mac}) as #{i.name} in #{i.network}.")
|
150
|
+
attrs = {
|
151
|
+
:name => i.name,
|
152
|
+
:network_name => i.network,
|
153
|
+
}
|
154
|
+
update_node_nic(node_instance, n, attrs)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def add_node_affinity(node_instance, name)
|
159
|
+
affinity_group = compute_provider.affinity_groups.find { |g| g.name == name }
|
160
|
+
raise ProviderError, "No such affinity group #{name}" unless affinity_group
|
161
|
+
::Dopv::log.info("Node #{nodename}: Adding node to affinity group #{name}.")
|
162
|
+
node_instance.add_to_affinity_group(:id => affinity_group.id)
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_node_volume(node_instance, config)
|
166
|
+
storage_domain = compute_provider.storage_domains.find { |d| d.name == config.pool }
|
167
|
+
raise ProviderError, "No such storage domain #{storage_domain_name}" unless storage_domain
|
168
|
+
|
169
|
+
node_instance.add_volume(
|
170
|
+
{
|
171
|
+
:alias => config.name,
|
172
|
+
:size => config.size.bytes,
|
173
|
+
:bootable => 'false',
|
174
|
+
:wipe_after_delete => 'true',
|
175
|
+
:storage_domain => storage_domain.id
|
176
|
+
}.tap { |h| (h[:format] = 'raw'; h[:sparse] = 'false') unless config.thin? }
|
177
|
+
)
|
178
|
+
wait_for_task_completion(node_instance)
|
179
|
+
node_instance.volumes.find { |v| v.alias == config.name } # TODO: Rewrite with volume.reload if possible
|
180
|
+
end
|
181
|
+
|
182
|
+
def destroy_node_volume(node_instance, volume)
|
183
|
+
node_instance.destroy_volume(:id => volume.id)
|
184
|
+
wait_for_task_completion(node_instance)
|
185
|
+
node_instance.volumes.reload
|
186
|
+
end
|
187
|
+
|
188
|
+
def attach_node_volume(node_instance, volume)
|
189
|
+
node_instance.attach_volume(:id => volume.id)
|
190
|
+
wait_for_task_completion(node_instance)
|
191
|
+
node_instance.volumes.reload
|
192
|
+
end
|
193
|
+
|
194
|
+
def detach_node_volume(node_instance, volume)
|
195
|
+
node_instance.detach_volume(:id => volume.id)
|
196
|
+
wait_for_task_completion(node_instance)
|
197
|
+
node_instance.volumes.reload
|
198
|
+
end
|
199
|
+
|
200
|
+
def record_node_data_volume(volume)
|
201
|
+
super(
|
202
|
+
:name => volume.alias,
|
203
|
+
:id => volume.id,
|
204
|
+
:pool => volume.storage_domain,
|
205
|
+
:size => volume.size
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
def provider_ca_cert_file
|
210
|
+
uri = infrastructure.endpoint
|
211
|
+
local_ca_file = "#{TMP}/#{uri.host}_#{uri.port}_ca.crt"
|
212
|
+
remote_ca_file = "#{uri.scheme}://#{uri.host}:#{uri.port}/ca.crt"
|
213
|
+
unless File.exists?(local_ca_file)
|
214
|
+
begin
|
215
|
+
open(remote_ca_file, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE) do |remote_ca|
|
216
|
+
local_ca = open(local_ca_file, 'w')
|
217
|
+
local_ca.write(remote_ca.read)
|
218
|
+
local_ca.close
|
219
|
+
end
|
220
|
+
rescue
|
221
|
+
raise ProviderError, "Cannot download CA certificate from #{provider_url}"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
local_ca_file
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|