Statistics
| Branch: | Tag: | Revision:

one / src / onedb / vcenter_one54_pre.rb @ 4944a4ae

History | View | Annotate | Download (129 KB)

1
#!/usr/bin/env ruby
2

    
3
# -------------------------------------------------------------------------- #
4
# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                #
5
#                                                                            #
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
7
# not use this file except in compliance with the License. You may obtain    #
8
# a copy of the License at                                                   #
9
#                                                                            #
10
# http://www.apache.org/licenses/LICENSE-2.0                                 #
11
#                                                                            #
12
# Unless required by applicable law or agreed to in writing, software        #
13
# distributed under the License is distributed on an "AS IS" BASIS,          #
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
15
# See the License for the specific language governing permissions and        #
16
# limitations under the License.                                             #
17
#--------------------------------------------------------------------------- #
18

    
19
ONE_LOCATION = ENV["ONE_LOCATION"]
20

    
21
if !ONE_LOCATION
22
    RUBY_LIB_LOCATION = "/usr/lib/one/ruby"
23
    REMOTES_LOCATION  = "/var/lib/one/remotes/"
24
else
25
    RUBY_LIB_LOCATION = ONE_LOCATION+"/lib/ruby"
26
    REMOTES_LOCATION  = ONE_LOCATION+"/var/remotes/"
27
end
28

    
29
$: << RUBY_LIB_LOCATION
30
$: << RUBY_LIB_LOCATION+"/cli"
31
$: << REMOTES_LOCATION+"vmm/vcenter/"
32

    
33
require 'fileutils'
34

    
35
require 'command_parser'
36
require 'one_helper/onehost_helper'
37
require 'one_helper/onecluster_helper'
38
require 'vcenter_driver'
39
require 'opennebula'
40

    
41
TEMP_DIR="/var/tmp/vcenter_one54"
42

    
43
FileUtils.mkdir_p TEMP_DIR
44

    
45
def banner(msg, header=false, extended=nil)
46
    STDOUT.puts
47
    STDOUT.puts if !header
48
    STDOUT.puts "="*80
49
    STDOUT.puts msg
50
    STDOUT.puts "-"*80 if extended
51
    STDOUT.puts extended if extended
52
    STDOUT.puts "="*80
53
end
54

    
55
def logo_banner(msg, header=false)
56

    
57
    STDOUT.puts
58
    STDOUT.puts if !header
59
    STDOUT.puts "="*80
60
    STDOUT.puts " / _ \\ _ __   ___ _ __ | \\ | | ___| |__  _   _| | __ _"
61
    STDOUT.puts "| | | | '_ \\ / _ \\ '_ \\|  \\| |/ _ \\ '_ \\| | | | |/ _` |"
62
    STDOUT.puts "| |_| | |_) |  __/ | | | |\\  |  __/ |_) | |_| | | (_| |"
63
    STDOUT.puts " \\___/| .__/ \\___|_| |_|_| \\_|\\___|_.__/ \\__,_|_|\\__,_|"
64
    STDOUT.puts "      |_|"
65
    STDOUT.puts "-"*80
66
    STDOUT.puts msg
67
    STDOUT.puts "="*80
68
end
69

    
70
################################################################################
71
# Monkey patch XMLElement with retrieve_xmlelements
72
################################################################################
73

    
74
class OpenNebula::XMLElement
75
    def retrieve_xmlelements(xpath_str)
76
        collection = []
77
        if OpenNebula::NOKOGIRI
78
            @xml.xpath(xpath_str).each { |pelem|
79
                collection << OpenNebula::XMLElement.new(pelem)
80
            }
81
        else
82
            @xml.elements.each(xpath_str) { |pelem|
83
                collection << OpenNebula::XMLElement.new(pelem)
84
            }
85
        end
86
        collection
87
    end
88
end
89

    
90
def get_image_size(ds, img_str)
91
    ds_name = ds.name
92

    
93
    img_path = File.dirname img_str
94
    img_name = File.basename img_str
95

    
96
    # Create Search Spec
97
    spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new
98

    
99
    vmdisk_query = RbVmomi::VIM::VmDiskFileQuery.new
100
    vmdisk_query.details = RbVmomi::VIM::VmDiskFileQueryFlags(:diskType        => true,
101
                                                              :capacityKb      => true,
102
                                                              :hardwareVersion => true,
103
                                                              :controllerType  => true)
104

    
105
    spec.query   = [vmdisk_query, RbVmomi::VIM::IsoImageFileQuery.new]
106
    spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner    => true,
107
                                                :fileSize     => true,
108
                                                :fileType     => true,
109
                                                :modification => true)
110

    
111
    spec.matchPattern = img_name.nil? ? [] : [img_name]
112

    
113
    datastore_path = "[#{ds_name}]"
114
    datastore_path << " #{img_path}" if !img_path.nil?
115

    
116
    search_params = {'datastorePath' => datastore_path, 'searchSpec'    => spec}
117

    
118
    # Perform search task and return results
119
    begin
120
        search_task = ds.browser.SearchDatastoreSubFolders_Task(search_params)
121

    
122
        search_task.wait_for_completion
123

    
124
        size = 0
125

    
126
        # Try to get vmdk capacity as seen by VM
127
        size = search_task.info.result[0].file[0].capacityKb / 1024 rescue nil
128

    
129
        # Try to get file size
130
        size = search_task.info.result[0].file[0].fileSize / 1024 / 1024 rescue nil if !size
131

    
132
        raise "Could not get file size or capacity" if size.nil?
133

    
134
        size
135
    rescue
136
        raise "Could not find file #{img_path}."
137
    end
138
end
139

    
140
def create_cdata_element(item, xml_doc, element_name, element_value)
141
    item.add_child(xml_doc.create_element(element_name)).add_child(Nokogiri::XML::CDATA.new(xml_doc,element_value))
142
end
143

    
144
def create_disk(xml_doc, image_name, image_source, image_prefix, image_id,
145
                disk_index, cluster_id, ds, ds_ref, ds_name, vi_client)
146

    
147
    disk_size = get_image_size(RbVmomi::VIM::Datastore.new(vi_client.vim, ds_ref), image_source)
148
    device_letters = ('a'..'z').to_a
149

    
150
    # Add new disk attributes
151
    xml_template   = xml_doc.root.at_xpath("TEMPLATE")
152
    disk = xml_template.add_child(xml_doc.create_element("DISK"))
153
    create_cdata_element(disk, xml_doc, "CLONE", "YES")
154
    create_cdata_element(disk, xml_doc, "CLONE_TARGET", "SYSTEM")
155
    create_cdata_element(disk, xml_doc, "CLUSTER_ID", "#{cluster_id}")
156
    create_cdata_element(disk, xml_doc, "DATASTORE", "#{ds_name}")
157
    create_cdata_element(disk, xml_doc, "DATASTORE_ID", "#{ds["ID"]}")
158
    create_cdata_element(disk, xml_doc, "DEV_PREFIX", "#{image_prefix}")
159
    create_cdata_element(disk, xml_doc, "DISK_ID", "#{disk_index}")
160
    create_cdata_element(disk, xml_doc, "DISK_SNAPSHOT_TOTAL_SIZE", "0")
161
    create_cdata_element(disk, xml_doc, "DISK_TYPE", "FILE")
162
    create_cdata_element(disk, xml_doc, "IMAGE", "#{image_name}")
163
    create_cdata_element(disk, xml_doc, "IMAGE_ID", "#{image_id}")
164
    create_cdata_element(disk, xml_doc, "IMAGE_STATE", "2")
165
    create_cdata_element(disk, xml_doc, "LN_TARGET", "NONE")
166
    create_cdata_element(disk, xml_doc, "OPENNEBULA_MANAGED", "NO")
167
    create_cdata_element(disk, xml_doc, "ORIGINAL_SIZE", "#{disk_size}")
168
    create_cdata_element(disk, xml_doc, "READONLY", "NO")
169
    create_cdata_element(disk, xml_doc, "SAVE", "NO")
170
    create_cdata_element(disk, xml_doc, "SIZE", "#{disk_size}")
171
    create_cdata_element(disk, xml_doc, "SOURCE", "#{image_source}")
172
    create_cdata_element(disk, xml_doc, "TARGET", "#{image_prefix}#{device_letters[disk_index]}")
173
    create_cdata_element(disk, xml_doc, "TM_MAD", "vcenter")
174
    create_cdata_element(disk, xml_doc, "TYPE", "FILE")
175
    create_cdata_element(disk, xml_doc, "VCENTER_ADAPTER_TYPE","#{ds["TEMPLATE/VCENTER_DS_REF"]}")
176
    create_cdata_element(disk, xml_doc, "VCENTER_DISK_TYPE", "#{ds["TEMPLATE/VCENTER_DS_REF"]}")
177
    create_cdata_element(disk, xml_doc, "VCENTER_DS_REF", "#{ds["TEMPLATE/VCENTER_DS_REF"]}")
178
end
179

    
180
def create_nic(xml_doc, network, mac_address, cluster_id, nic_index)
181
    xml_template   = xml_doc.root.at_xpath("TEMPLATE")
182
    nic = xml_template.add_child(xml_doc.create_element("NIC"))
183
    create_cdata_element(nic, xml_doc, "BRIDGE", "#{network["BRIDGE"]}")
184
    create_cdata_element(nic, xml_doc, "CLUSTER_ID", "#{cluster_id}")
185
    create_cdata_element(nic, xml_doc, "MAC", "#{mac_address}")
186
    create_cdata_element(nic, xml_doc, "NETWORK", "#{network["NAME"]}")
187
    create_cdata_element(nic, xml_doc, "NETWORK_ID", "#{network["ID"]}")
188
    create_cdata_element(nic, xml_doc, "NIC_ID", "#{nic_index}")
189
    create_cdata_element(nic, xml_doc, "OPENNEBULA_MANAGED", "NO")
190
    create_cdata_element(nic, xml_doc, "SECURITY_GROUPS", "0")
191
    create_cdata_element(nic, xml_doc, "VCENTER_CCR_REF", "#{network["TEMPLATE/VCENTER_CCR_REF"]}")
192
    create_cdata_element(nic, xml_doc, "VCENTER_INSTANCE_ID", "#{network["TEMPLATE/VCENTER_INSTANCE_ID"]}")
193
    create_cdata_element(nic, xml_doc, "VCENTER_NET_REF", "#{network["TEMPLATE/VCENTER_NET_REF"]}")
194
    create_cdata_element(nic, xml_doc, "VCENTER_PORTGROUP_TYPE", "#{network["TEMPLATE/VCENTER_PORTGROUP_TYPE"]}")
195
    create_cdata_element(nic, xml_doc, "VN_MAD", "dummy")
196
end
197

    
198
def create_image_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, ccr_name, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id=nil)
199
    image_ds_name = "#{ds_name}"
200
    template  = ""
201
    template  << "NAME=\"#{image_ds_name}\"\n"
202
    template  << "TM_MAD=vcenter\n"
203
    template  << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
204
    template  << "VCENTER_DS_REF=\"#{ds_ref}\"\n"
205
    template  << "VCENTER_DC_REF=\"#{dc_ref}\"\n"
206
    template  << "VCENTER_DS_NAME=\"#{ds_name}\"\n"
207
    template  << "VCENTER_DC_NAME=\"#{dc_name}\"\n"
208
    template  << "VCENTER_CLUSTER=\"#{ccr_name}\"\n"
209
    template  << "TYPE=IMAGE_DS\n"
210
    template  << "DS_MAD=vcenter\n"
211

    
212
    one_ds = OpenNebula::Datastore.new(OpenNebula::Datastore.build_xml, one_client)
213
    rc = one_ds.allocate(template)
214
    raise rc.message if OpenNebula.is_error?(rc)
215

    
216
    rc = one_ds.info
217
    raise rc.message if OpenNebula.is_error?(rc)
218

    
219
    # Wait till the DS is monitored
220
    loop do
221
        sleep(2)
222
        one_ds.info
223
        break if one_ds["STATE"].to_i == 0 && one_ds["TOTAL_MB"].to_i > 0
224
    end
225

    
226
    STDOUT.puts "--- New IMAGE datastore #{image_ds_name} created with ID: #{one_ds["ID"]}!\n"
227

    
228
    return one_ds
229
end
230

    
231
def create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_host, vcenter_user, vcenter_pass, cluster_id=nil)
232
    system_ds_name = "#{ds_name} (SYS)"
233
    template  = ""
234
    template  << "NAME=\"#{system_ds_name}\"\n"
235
    template  << "TM_MAD=vcenter\n"
236
    template  << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
237
    template  << "VCENTER_DC_REF=\"#{dc_ref}\"\n"
238
    template  << "VCENTER_DC_NAME=\"#{dc_name}\"\n"
239
    template  << "VCENTER_DS_REF=\"#{ds_ref}\"\n"
240
    template  << "VCENTER_DS_NAME=\"#{ds_name}\"\n"
241
    template  << "VCENTER_USER=\"#{vcenter_user}\"\n" if vcenter_user
242
    template  << "VCENTER_PASSWORD=\"#{vcenter_pass}\"\n" if vcenter_pass
243
    template  << "VCENTER_HOST=\"#{vcenter_host}\"\n" if vcenter_host
244
    template  << "TYPE=SYSTEM_DS\n"
245

    
246
    one_ds = OpenNebula::Datastore.new(OpenNebula::Datastore.build_xml, one_client)
247
    if cluster_id
248
        rc = one_ds.allocate(template, cluster_id.to_i)
249
    else
250
        rc = one_ds.allocate(template)
251
    end
252
    raise rc.message if OpenNebula.is_error?(rc)
253

    
254
    one_ds.info
255
    rc = one_ds.info
256
    raise rc.message if OpenNebula.is_error?(rc)
257

    
258
    STDOUT.puts "Datastore \e[96m#{ds_name}\e[39m is now also a SYSTEM datastore with ID: #{one_ds["ID"]}\n"
259
    one_ds
260
end
261

    
262
def get_dc(item)
263
    while !item.instance_of? RbVmomi::VIM::Datacenter
264
        item = item.parent
265
        raise "Could not find the parent Datacenter" if !item
266
    end
267
    return item
268
end
269

    
270
def find_image(ipool, ds_name, image_path)
271
    element = ipool.select do |e|
272
        e["SOURCE"] == image_path &&
273
        e["DATASTORE"] == ds_name
274

    
275
    end.first rescue nil
276

    
277
    return element
278
end
279

    
280
def find_datastore_by_name(dspool, name)
281
    element = dspool.select do |e|
282
        e["NAME"] == name
283
    end.first rescue nil
284

    
285
    return element
286
end
287

    
288
def find_cluster_by_name(cpool, name)
289
    element = cpool.select do |e|
290
        e["NAME"] == name
291
    end.first rescue nil
292

    
293
    return element
294
end
295

    
296
def find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, type)
297
    element = dspool.select do |e|
298
        e["TEMPLATE/TYPE"]                == type &&
299
        e["TEMPLATE/VCENTER_DS_REF"]      == ds_ref &&
300
        e["TEMPLATE/VCENTER_DC_REF"]      == dc_ref &&
301
        e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid
302
    end.first rescue nil
303

    
304
    return element
305
end
306

    
307
def find_network(vnpool, net_ref, ccr_ref, template_ref, vcenter_uuid)
308
    element = vnpool.select do |e|
309
        e["TEMPLATE/VCENTER_NET_REF"]      == net_ref &&
310
        e["TEMPLATE/VCENTER_TEMPLATE_REF"] == template_ref &&
311
        e["TEMPLATE/VCENTER_CCR_REF"]      == ccr_ref &&
312
        e["TEMPLATE/VCENTER_INSTANCE_ID"]  == vcenter_uuid &&
313
        e["TEMPLATE/OPENNEBULA_MANAGED"] == "NO"
314
    end.first rescue nil
315

    
316
    return element
317
end
318

    
319
def find_template(tpool, template_id, template_ref, ccr_ref, vcenter_uuid)
320
    element = tpool.select do |e|
321
        e["ID"] == template_id &&
322
        e["TEMPLATE/VCENTER_TEMPLATE_REF"] == template_ref &&
323
        e["TEMPLATE/VCENTER_CCR_REF"]      == ccr_ref &&
324
        e["TEMPLATE/VCENTER_INSTANCE_ID"]  == vcenter_uuid
325
    end.first rescue nil
326

    
327
    return element
328
end
329

    
330
def vm_unmanaged_discover(devices, xml_doc, template_xml,
331
                          existing_disks, existing_nics, ccr_name, ccr_ref,
332
                          vcenter_name, vcenter_uuid, vcenter_user, vcenter_pass, vcenter_host,
333
                          dc_name, dc_ref, ipool, vnpool, dspool, hpool,
334
                          one_client, vi_client, vm_wild, vm_id, vm_name, vc_templates,
335
                          vm_ref, vc_vmachines, template_ref, one_clusters, vcenter_ids)
336
    unmanaged = {}
337
    unmanaged[:images] = []
338
    unmanaged[:networks] = []
339

    
340
    ide_controlled  = []
341
    sata_controlled = []
342
    scsi_controlled = []
343

    
344
    disk_index           = 0
345
    unmanaged_disk_index = 0
346
    managed_disk_index   = 0
347
    nic_index            = 0
348
    managed_nic_index    = 0
349

    
350
    extraconfig   = []
351

    
352
    # Get cluster's host ID
353
    hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
354
    if hosts.empty?
355
        raise "Cannot find cluster's host ID associated with this template."
356
    end
357
    host_id = hosts.first["ID"]
358

    
359
    if !one_clusters.key?(host_id)
360
        raise "Could not find the OpenNebula cluster ID that is going to be associated to images and networks found in the template."
361
    end
362

    
363
    cluster_id = one_clusters[host_id]
364

    
365
    if !vm_wild && template_xml
366
        devices.each do |device|
367
            rc = vnpool.info_all
368
            raise "\n    ERROR! Could not update vnpool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
369

    
370
            rc = ipool.info_all
371
            raise "\n    ERROR! Could not update ipool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
372

    
373
            rc = dspool.info
374
            raise "\n    ERROR! Could not update dspool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
375

    
376
            if defined?(RbVmomi::VIM::VirtualIDEController) &&
377
               device.is_a?(RbVmomi::VIM::VirtualIDEController)
378
                ide_controlled += device.device
379
                next
380
            end
381

    
382
            if defined?(RbVmomi::VIM::VirtualSATAController) &&
383
               device.is_a?(RbVmomi::VIM::VirtualSATAController)
384
                sata_controlled += device.device
385
                next
386
            end
387

    
388
            if defined?(RbVmomi::VIM::VirtualSCSIController) &&
389
               device.is_a?(RbVmomi::VIM::VirtualSCSIController)
390
                scsi_controlled += device.device
391
                next
392
            end
393

    
394
            #cluster_id = xml_doc.root.xpath("HISTORY_RECORDS/HISTORY[last()]/CID").text
395

    
396
            # If CDROM
397
            if !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil?
398
                device_backing_datastore = device.backing.datastore rescue nil
399
                if device_backing_datastore
400
                    ds_name       = device.backing.datastore.name
401
                    ds_ref        = device.backing.datastore._ref
402
                    image_path    = device.backing.fileName.sub(/^\[(.*?)\] /, "")
403

    
404
                    image = find_image(ipool, ds_name, image_path)
405

    
406
                    if image
407
                        # It's a persistent disk if it already exists
408
                        xml_template     = xml_doc.root.at_xpath("TEMPLATE")
409
                        existing_disk    = existing_disks[managed_disk_index]
410

    
411
                        # Replace DISK_ID
412
                        existind_disk_id = existing_disk.at_xpath("DISK_ID")
413
                        existind_disk_id.content = disk_index
414

    
415
                        disk = xml_template.add_child(existing_disks[managed_disk_index])
416

    
417
                        # Add VCENTER_DS_REF
418
                        disk.add_child(xml_doc.create_element("VCENTER_DS_REF")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{ds_ref}"))
419

    
420
                        STDOUT.puts "--- Added VCENTER_DS_REF=#{ds_ref} to CDROM (IMAGE_ID=#{image["ID"]})"
421

    
422
                        # Update indexes
423
                        managed_disk_index = managed_disk_index + 1
424
                        disk_index = disk_index + 1
425
                    end
426
                end
427
            end
428

    
429
            # If Virtual Disk
430
            if !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil?
431
                ds_name       = device.backing.datastore.name
432
                ds_ref        = device.backing.datastore._ref
433
                image_type    = "OS"
434
                image_path    = device.backing.fileName.sub(/^\[(.*?)\] /, "")
435
                image_prefix  = "hd" if ide_controlled.include?(device.key)
436
                image_prefix  = "sd" if scsi_controlled.include?(device.key)
437
                image_prefix  = "sd" if sata_controlled.include?(device.key)
438
                file_name     = File.basename(image_path).gsub(/\.vmdk$/,"")
439
                image_name    = "#{file_name} - #{ds_name}"
440

    
441
                #Check if the image already exists
442
                one_image = find_image(ipool, ds_name, image_path)
443

    
444
                if !one_image
445
                    #Check if the IMAGE DS is there
446
                    ds = find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, "IMAGE_DS")
447

    
448
                    #Create IMAGE and SYSTEM DS if datastore is not found
449
                    if !ds
450
                        ds = create_image_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, ccr_name, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
451

    
452
                        create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
453
                    end
454

    
455
                    ds_id = ds["ID"].to_i
456

    
457
                    template_disk = template_xml.xpath("VMTEMPLATE/TEMPLATE/DISK")[unmanaged_disk_index] rescue nil
458
                    raise "Cannot find unmanaged disk inside template" if !template_disk
459

    
460
                    image_id = template_disk.xpath("IMAGE_ID").text
461
                    raise "Cannot find image id for unmanaged disk" if image_id.empty?
462

    
463
                    one_image = OpenNebula::Image.new_with_id(image_id, one_client)
464
                    rc = one_image.info
465
                    raise "\n    ERROR! Could not get image info for unmanaged disk. image_id '#{image_id}'. Reason #{rc.message}" if OpenNebula.is_error?(rc)
466

    
467
                    ds_id = one_image['DATASTORE_ID']
468
                    ds = OpenNebula::Datastore.new_with_id(ds_id, one_client)
469
                    rc = ds.info
470
                    raise "\n    ERROR! Could not get ds info. Reason #{rc.message}" if OpenNebula.is_error?(rc)
471

    
472
                    ds_ref = ds["TEMPLATE/VCENTER_DS_REF"]
473
                    ds_name = ds["NAME"]
474

    
475
                    STDOUT.puts "--- Image #{one_image["NAME"]} with ID #{one_image["ID"]} already exists"
476

    
477
                    # Create unmanaged disk element for vm template
478
                    # Get disk size (capacity)
479
                    image_name   = one_image["NAME"]
480
                    image_source = one_image["SOURCE"]
481
                    image_id     = one_image["ID"]
482

    
483
                    # Add new disk attributes
484
                    create_disk(xml_doc, image_name, image_source, image_prefix, image_id,
485
                                disk_index, cluster_id, ds, ds_ref, ds_name, vi_client)
486

    
487
                    STDOUT.puts "--- Added unmanaged disk to xml template (IMAGE_ID=#{one_image["ID"]})"
488

    
489
                    reference = {}
490
                    reference[:key]   = "opennebula.disk.#{unmanaged_disk_index}"
491
                    reference[:value] = "#{device.key}"
492
                    extraconfig << reference
493

    
494
                    unmanaged_disk_index = unmanaged_disk_index + 1
495
                    disk_index = disk_index + 1
496
                else
497
                    if one_image["TEMPLATE/VCENTER_IMPORTED"] == "YES"
498
                        # This is (probably) a wild VM. The code should not reach this.
499

    
500
                        #Check if the IMAGE DS is there
501
                        ds = find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, "IMAGE_DS")
502

    
503
                        #Create IMAGE and SYSTEM DS if datastore is not found
504
                        if !ds
505
                            ds = create_image_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, ccr_name, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
506

    
507
                            create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
508
                        end
509

    
510
                        ds_id = ds["ID"].to_i
511

    
512
                        #Create unmanaged disk element for vm template
513
                        image_id     = one_image["ID"]
514
                        image_name   = one_image["NAME"]
515
                        image_source = one_image["SOURCE"]
516

    
517
                        create_disk(xml_doc, image_name, image_source, image_prefix, image_id,
518
                                    disk_index, cluster_id, ds, ds_ref, ds_name, vi_client)
519

    
520
                        STDOUT.puts "--- Added unmanaged disk in wild vm (IMAGE_ID=#{one_image["ID"]})"
521

    
522
                        reference = {}
523
                        reference[:key]   = "opennebula.disk.#{unmanaged_disk_index}"
524
                        reference[:value] = "#{device.key}"
525
                        extraconfig << reference
526

    
527
                        # Update indexes
528
                        unmanaged_disk_index = unmanaged_disk_index + 1
529
                        disk_index = disk_index + 1
530

    
531
                    else
532
                        # It's a persistent disk if it already exists
533
                        xml_template  = xml_doc.root.at_xpath("TEMPLATE")
534
                        existing_disk = existing_disks[managed_disk_index]
535

    
536
                        # Replace DISK_ID
537
                        existing_disk_image_id = existing_disk.xpath("IMAGE_ID").text
538
                        existing_disk_id = existing_disk.at_xpath("DISK_ID")
539
                        existing_disk_id.content = disk_index
540

    
541
                        disk = xml_template.add_child(existing_disks[managed_disk_index])
542

    
543
                        # Add VCENTER_DISK_TYPE and VCENTER_ADAPTER_TYPE if found
544
                        if !existing_disk.xpath("DISK_TYPE").text.empty?
545
                            disk.add_child(xml_doc.create_element("VCENTER_DISK_TYPE")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{existing_disk.xpath("DISK_TYPE").text}"))
546
                            STDOUT.puts "--- Added VCENTER_DISK_TYPE=#{existing_disk.xpath("DISK_TYPE").text} to existing disk (IMAGE_ID=#{existing_disk_image_id})"
547
                        end
548

    
549
                        if !existing_disk.xpath("ADAPTER_TYPE").text.empty?
550
                            disk.add_child(xml_doc.create_element("VCENTER_ADAPTER_TYPE")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{existing_disk.xpath("ADAPTER_TYPE").text}"))
551
                            STDOUT.puts "--- Added VCENTER_ADAPTER_TYPE=#{existing_disk.xpath("ADAPTER_TYPE").text} to existing disk (IMAGE_ID=#{existing_disk_image_id})"
552
                        end
553

    
554
                        # Add VCENTER_DS_REF
555
                        disk.add_child(xml_doc.create_element("VCENTER_DS_REF")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{ds_ref}"))
556
                        STDOUT.puts "--- Added VCENTER_DS_REF=#{ds_ref} to existing disk (IMAGE_ID=#{existing_disk_image_id})"
557

    
558
                        # Update indexes
559
                        managed_disk_index = managed_disk_index + 1
560
                        disk_index = disk_index + 1
561
                    end
562
                end
563
            end
564

    
565
            # If VirtualEthernetCard
566
            if !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil?
567
                network_bridge = device.backing.network.name
568
                network_ref    = device.backing.network._ref
569
                network_name   = "#{network_bridge} [#{vm_name}]"
570
                network_type   = device.backing.network.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) ? "Distributed Port Group" : "Port Group"
571

    
572
                # Create network if doesn't exist
573
                network = find_network(vnpool, network_ref, ccr_ref, template_ref, vcenter_uuid)
574

    
575
                if !network
576
                    one_net = ""
577
                    one_net << "NAME=\"#{network_name}\"\n"
578
                    one_net << "BRIDGE=\"#{network_bridge}\"\n"
579
                    one_net << "VN_MAD=\"dummy\"\n"
580
                    one_net << "VCENTER_PORTGROUP_TYPE=\"#{network_type}\"\n"
581
                    one_net << "VCENTER_NET_REF=\"#{network_ref}\"\n"
582
                    one_net << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"
583
                    one_net << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
584
                    one_net << "VCENTER_TEMPLATE_REF=\"#{template_ref}\"\n"
585
                    one_net << "OPENNEBULA_MANAGED=\"NO\"\n"
586
                    one_net << "AR=[\n"
587
                    one_net << "TYPE=\"ETHER\",\n"
588
                    one_net << "SIZE=\"255\"\n"
589
                    one_net << "]\n"
590

    
591
                    one_vn = OpenNebula::VirtualNetwork.new(OpenNebula::VirtualNetwork.build_xml, one_client)
592
                    rc = one_vn.allocate(one_net, cluster_id.to_i)
593
                    raise "\n    ERROR! Could not create vnet for vm #{vm_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
594

    
595
                    rc = one_vn.info
596
                    raise "\n    ERROR! Could not get network info for vnet #{network_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
597
                    network = one_vn
598
                    STDOUT.puts "--- Network #{one_vn["NAME"]} with ID #{one_vn["ID"]} has been created"
599
                else
600
                    STDOUT.puts "--- Network #{network["NAME"]} with ID #{network["ID"]} already exists"
601
                end
602

    
603
                existing_macs = []
604
                existing_nics.xpath("MAC").each do |mac|
605
                    existing_macs << mac.text
606
                end
607

    
608
                mac_address = device.macAddress
609
                if !existing_macs.include?(mac_address)
610
                    # Unmanaged nic
611
                    create_nic(xml_doc, network, mac_address, cluster_id, nic_index)
612

    
613
                    #Update indexes
614
                    nic_index = nic_index + 1
615
                else
616
                    # Managed nic
617
                    managed_nic_index = existing_macs.index(mac_address)
618
                    xml_template      = xml_doc.root.at_xpath("TEMPLATE")
619
                    existing_nic      = existing_nics[managed_nic_index]
620

    
621
                    # Replace NIC_ID
622
                    existind_nic_id = existing_nic.at_xpath("NIC_ID")
623
                    existind_nic_id.content = nic_index
624

    
625
                    # Add existing NIC to XML template
626
                    nic = xml_template.add_child(existing_nics[managed_nic_index])
627
                    create_cdata_element(nic, xml_doc, "VCENTER_NET_REF", "#{network["TEMPLATE/VCENTER_NET_REF"]}")
628
                    create_cdata_element(nic, xml_doc, "VCENTER_CCR_REF", "#{network["TEMPLATE/VCENTER_CCR_REF"]}")
629
                    create_cdata_element(nic, xml_doc, "VCENTER_INSTANCE_ID", "#{network["TEMPLATE/VCENTER_INSTANCE_ID"]}")
630
                    create_cdata_element(nic, xml_doc, "VCENTER_PORTGROUP_TYPE", "#{network["TEMPLATE/VCENTER_PORTGROUP_TYPE"]}")
631

    
632
                    #Update indexes
633
                    nic_index = nic_index + 1
634
                end
635
            end
636
        end
637
    end
638

    
639
    # Reference some nodes
640
    xml_template = xml_doc.root.at_xpath("TEMPLATE")
641
    xml_user_template = xml_doc.root.at_xpath("USER_TEMPLATE")
642
    xml_monitoring = xml_doc.root.at_xpath("MONITORING")
643
    xml_history = xml_doc.root.at_xpath("HISTORY_RECORDS/HISTORY")
644

    
645
    # Update context disk ID
646
    if !vm_wild
647
        xml_template.xpath("CONTEXT/DISK_ID").remove
648
        xml_context  = xml_template.at_xpath("CONTEXT")
649
        xml_context.add_child(xml_doc.create_element("DISK_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{disk_index}"))
650
    end
651

    
652
    # Remove PUBLIC_CLOUD as it is no longer used with vcenter
653
    xml_user_template.xpath("PUBLIC_CLOUD").remove
654

    
655
    # Remove KEEP_DISKS_ON_DONE from USER_TEMPLATE
656
    xml_user_template.xpath("KEEP_DISKS_ON_DONE").remove
657

    
658
    # Remove SCHED_DS_REQUIREMENTS
659
    xml_user_template.xpath("SCHED_DS_REQUIREMENTS").remove
660

    
661
    # Remove VCENTER_DATASTORE and USER_INPUTS/VCENTER_DATASTORE... no longer used
662
    # If datastore is a system_ds we may have to add SCHED_DS_REQUIREMENTS
663
    # Also identify the datastore id to update last history records with the new DS_ID
664

    
665
    vcenter_datastore = xml_user_template.xpath("VCENTER_DATASTORE").text
666
    ds_id = nil
667
    if !vcenter_datastore.empty?
668
        # If VCENTER_DATASTORE is a SYSTEM_DS it is a StoragePod then
669
        # SCHED_DS_REQUIREMENTS must contain ID="DS_ID"
670
        ds      = find_datastore_by_name(dspool, "#{vcenter_datastore}")
671
        ds_id   = ds["ID"]
672
        ds_type = ds["TEMPLATE/TYPE"]
673
        if ds_type == "SYSTEM_DS"
674
            sched_ds_req = xml_user_template.xpath("SCHED_DS_REQUIREMENTS")
675
            if !sched_ds_req.empty?
676
                xml_user_template.xpath("SCHED_DS_REQUIREMENTS").remove
677
                requirements = "ID=#{ds_id} & (#{sched_ds_req})"
678
                xml_user_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"#{requirements}\""))
679
            else
680
                # Add a SCHED_DS_REQUIREMENTS to template
681
                xml_user_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"ID=#{ds_id}\""))
682
            end
683
        end
684

    
685
        # New ds should be a system datastore
686
        ds = find_datastore_by_name(dspool, "#{vcenter_datastore} (SYS)")
687
        ds_id = ds["ID"]
688
    else
689
        if vm_wild
690
            if !vc_vmachines.key? vm_ref
691
                raise "Could not find vcenter vm using ref #{vm_ref} in order to assign a datastore"
692
            else
693
                vc_system_ds = vc_vmachine["datastore"].first rescue nil
694
                raise "Could not find Datastore associated with the VM" if vc_system_ds.nil?
695

    
696
                ds_ref = vc_system_ds._ref
697

    
698
                ds = find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, "SYSTEM_DS")
699
                if !ds
700
                    ds_name = vc_system_ds.name
701
                    ds = create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
702
                end
703
                ds_id = ds["ID"]
704
            end
705
        else
706
            if !vc_templates.key? template_ref
707
                raise "Could not find vcenter template using ref #{template_ref} in order to assign a datastore"
708
            else
709
                ds_ref = vc_templates[template_ref]["datastore"].first._ref rescue nil
710
                raise "Could not get ds ref in order to assign a datastore in history records" if !ds_ref
711

    
712
                ds = find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, "SYSTEM_DS")
713
                ds_id = ds["ID"]
714
            end
715
        end
716
    end
717

    
718
    # Remove some attributes
719
    xml_user_template.xpath("VCENTER_DATASTORE").remove
720
    xml_user_template.xpath("USER_INPUTS/VCENTER_DATASTORE").remove
721
    xml_user_template.xpath("SCHED_REQUIREMENTS").remove
722

    
723
    # Replace USER_TEMPLATE/RESOURCE_POOL with VCENTER_RESOURCE_POOL
724
    resource_pool = xml_user_template.xpath("RESOURCE_POOL").text
725
    if !resource_pool.empty?
726
        xml_user_template.xpath("RESOURCE_POOL").remove
727
        vcenter_rp = xml_user_template.xpath("VCENTER_RESOURCE_POOL").text
728
        if !vcenter_rp.empty?
729
            xml_user_template.xpath("VCENTER_RESOURCE_POOL").remove
730
        end
731
        xml_user_template.add_child(xml_doc.create_element("VCENTER_RESOURCE_POOL")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{resource_pool}"))
732
    end
733

    
734
    # Replace USER_INPUTS/RESOURCE_POOL... no longer used
735
    user_resource_pool = xml_user_template.xpath("USER_INPUTS/RESOURCE_POOL").text
736
    if !user_resource_pool.empty?
737
        xml_user_template.xpath("USER_INPUTS/RESOURCE_POOL").remove
738
        vcenter_rp = xml_user_template.xpath("USER_INPUTS/VCENTER_RESOURCE_POOL").text
739
        if !vcenter_rp.empty?
740
            xml_user_template.xpath("USER_INPUTS/VCENTER_RESOURCE_POOL").remove
741
        end
742
        user_inputs = xml_user_template.at_xpath("USER_INPUTS")
743
        user_inputs.add_child(xml_doc.create_element("VCENTER_RESOURCE_POOL")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{user_resource_pool}"))
744
    end
745

    
746
    # Replace CUSTOMIZATION_SPEC with VCENTER_CUSTOMIZATION_SPEC
747
    customization_spec = xml_user_template.xpath("CUSTOMIZATION_SPEC").text
748
    if !customization_spec.empty?
749
        xml_user_template.xpath("CUSTOMIZATION_SPEC").remove
750
        xml_user_template.add_child(xml_doc.create_element("VCENTER_CUSTOMIZATION_SPEC")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{customization_spec}"))
751
    end
752

    
753
    # Add VCENTER_CCR_REF and VCENTER_INSTANCE_ID
754
    vcenter_ccr_ref = xml_user_template.xpath("VCENTER_CCR_REF").text
755
    if !vcenter_ccr_ref.empty?
756
        xml_user_template.xpath("VCENTER_CCR_REF").remove
757
    end
758
    xml_user_template.add_child(xml_doc.create_element("VCENTER_CCR_REF")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{ccr_ref}"))
759

    
760
    vcenter_instance_id = xml_user_template.xpath("VCENTER_INSTANCE_ID").text
761
    if !vcenter_instance_id.empty?
762
        xml_user_template.xpath("VCENTER_INSTANCE_ID").remove
763
    end
764
    xml_user_template.add_child(xml_doc.create_element("VCENTER_INSTANCE_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{vcenter_uuid}"))
765

    
766
    # Add VCENTER_TEMPLATE_REF if VM is not wild
767
    if !vm_wild
768
        vcenter_template_ref = xml_user_template.xpath("VCENTER_TEMPLATE_REF").text
769
        if !vcenter_template_ref.empty?
770
            xml_user_template.xpath("VCENTER_TEMPLATE_REF").remove
771
        end
772
        xml_user_template.add_child(xml_doc.create_element("VCENTER_TEMPLATE_REF")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{template_ref}"))
773
    end
774

    
775
    # Monitoring info attributes
776
    xml_monitoring.xpath("LAST_MON").remove
777

    
778
    esx_host = xml_monitoring.xpath("ESX_HOST").text
779
    if !esx_host.empty?
780
        xml_monitoring.xpath("ESX_HOST").remove
781
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_ESX_HOST")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{esx_host}"))
782
    end
783

    
784
    guest_state = xml_monitoring.xpath("GUEST_STATE").text
785
    if !guest_state.empty?
786
        xml_monitoring.xpath("GUEST_STATE").remove
787
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_GUEST_STATE")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{guest_state}"))
788
    end
789

    
790
    resource_pool = xml_monitoring.xpath("RESOURCE_POOL").text
791
    if !guest_state.empty?
792
        xml_monitoring.xpath("RESOURCE_POOL").remove
793
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_RP_NAME")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{resource_pool}"))
794
    end
795

    
796
    vmware_running_status = xml_monitoring.xpath("VMWARETOOLS_RUNNING_STATUS").text
797
    if !vmware_running_status.empty?
798
        xml_monitoring.xpath("VMWARETOOLS_RUNNING_STATUS").remove
799
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_VMWARETOOLS_RUNNING_STATUS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{vmware_running_status}"))
800
    end
801

    
802
    vmware_tools_version = xml_monitoring.xpath("VMWARETOOLS_VERSION").text
803
    if !vmware_tools_version.empty?
804
        xml_monitoring.xpath("VMWARETOOLS_VERSION").remove
805
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_VMWARETOOLS_VERSION")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{vmware_tools_version}"))
806
    end
807

    
808
    vmware_tools_version_status = xml_monitoring.xpath("VMWARETOOLS_VERSION_STATUS").text
809
    if !vmware_tools_version_status.empty?
810
        xml_monitoring.xpath("VMWARETOOLS_VERSION_STATUS").remove
811
        xml_monitoring.add_child(xml_doc.create_element("VCENTER_VMWARETOOLS_VERSION_STATUS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{vmware_tools_version_status}"))
812
    end
813

    
814
    # History record info attributes
815
    vmware_tools_version = xml_history.xpath("VMWARETOOLS_VERSION").text
816
    history_ds_id = xml_history.at_xpath("DS_ID")
817
    history_ds_id.content = ds_id
818
    xml_history.xpath("TM_MAD").remove
819
    xml_history.add_child(xml_doc.create_element("TM_MAD")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"vcenter"))
820

    
821
    # Write template to file
822
    File.open("#{TEMP_DIR}/one_migrate_vm_#{vm_id}","w"){|f| f.puts(xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<"))}
823
    STDOUT.puts
824
    STDOUT.puts "--- New XML file #{TEMP_DIR}/one_migrate_vm_#{vm_id} for vm \e[96m#{vm_name}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
825

    
826
    return extraconfig
827
end
828

    
829
def template_unmanaged_discover(devices, ccr_name, ccr_ref,
830
                                vcenter_name, vcenter_uuid,
831
                                vcenter_user, vcenter_pass, vcenter_host,
832
                                dc_name, dc_ref, ipool, vnpool, dspool, hpool,
833
                                one_client,
834
                                template_ref, template_name, template_id,
835
                                one_clusters, vcenter_ids)
836
    unmanaged = {}
837
    unmanaged[:images] = []
838
    unmanaged[:networks] = []
839

    
840
    ide_controlled  = []
841
    sata_controlled = []
842
    scsi_controlled = []
843

    
844
    # Get cluster's host ID
845
    hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
846
    if hosts.empty?
847
        raise "Cannot find cluster's host ID associated with this template."
848
    end
849
    host_id = hosts.first["ID"]
850

    
851
    if !one_clusters.key?(host_id)
852
        raise "Could not find the OpenNebula cluster ID that is going to be associated to images and networks found in the template."
853
    end
854

    
855
    cluster_id = one_clusters[host_id]
856

    
857
    # Loop through devices
858
    devices.each do |device|
859
        rc = vnpool.info_all
860
        raise "\n    ERROR! Could not update vnpool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
861

    
862
        rc = ipool.info_all
863
        raise "\n    ERROR! Could not update ipool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
864

    
865
        rc = dspool.info
866
        raise "\n    ERROR! Could not update dspool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
867

    
868
        if defined?(RbVmomi::VIM::VirtualIDEController) &&
869
           device.is_a?(RbVmomi::VIM::VirtualIDEController)
870
            ide_controlled += device.device
871
            next
872
        end
873

    
874
        if defined?(RbVmomi::VIM::VirtualSATAController) &&
875
           device.is_a?(RbVmomi::VIM::VirtualSATAController)
876
            sata_controlled += device.device
877
            next
878
        end
879

    
880
        if defined?(RbVmomi::VIM::VirtualSCSIController) &&
881
            device.is_a?(RbVmomi::VIM::VirtualSCSIController)
882
            scsi_controlled += device.device
883
            next
884
        end
885

    
886
        # If Virtual Disk
887
        if !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil?
888
            ds_name       = device.backing.datastore.name
889
            ds_ref        = device.backing.datastore._ref
890
            image_path    = device.backing.fileName.sub(/^\[(.*?)\] /, "")
891
            image_type    = "OS"
892
            image_prefix  = "hd" if ide_controlled.include?(device.key)
893
            image_prefix  = "sd" if scsi_controlled.include?(device.key)
894
            image_prefix  = "sd" if sata_controlled.include?(device.key)
895
            file_name     = File.basename(image_path).gsub(/\.vmdk$/,"")
896
            image_name    = "#{file_name} - #{ds_name} [Template #{template_id}]"
897

    
898
            #Check if the image has already been imported
899
            image = find_image(ipool, ds_name, image_path)
900

    
901
            #Check if the IMAGE DS is there
902
            ds = find_datastore(dspool, ds_ref, dc_ref, vcenter_uuid, "IMAGE_DS")
903

    
904
            #Create IMAGE and SYSTEM DS if datastore is not found
905
            if ds.nil?
906
                ds = create_image_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, ccr_name, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
907

    
908
                create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_user, vcenter_pass, vcenter_host, cluster_id)
909
            end
910

    
911
            if !image
912
                #Create image
913
                one_image = ""
914
                one_image << "NAME=\"#{image_name}\"\n"
915
                one_image << "PATH=\"vcenter://#{image_path}\"\n"
916
                one_image << "TYPE=\"#{image_type}\"\n"
917
                one_image << "PERSISTENT=\"NO\"\n"
918
                one_image << "VCENTER_IMPORTED=\"YES\"\n"
919
                one_image << "DEV_PREFIX=\"#{image_prefix}\"\n"
920

    
921
                one_i = OpenNebula::Image.new(OpenNebula::Image.build_xml, one_client)
922
                rc = one_i.allocate(one_image, ds["ID"].to_i)
923
                raise "\n    ERROR! Could not create image for template #{template_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
924

    
925
                rc = one_i.info
926
                raise "\n    ERROR! Could not get image info for template #{template_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
927
                STDOUT.puts "--- Image #{one_i["NAME"]} with ID #{one_i["ID"]} has been created"
928
                unmanaged[:images] << one_i["ID"]
929

    
930
                vcenter_ids[:image] << one_i["ID"]
931
            else
932
                unmanaged[:images] << image["ID"]
933
                STDOUT.puts "--- Image #{image["NAME"]} with ID #{image["ID"]} already exists"
934
            end
935
        end
936

    
937
        # If VirtualEthernetCard
938
        if !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil?
939
            network_bridge = device.backing.network.name
940
            network_ref    = device.backing.network._ref
941
            network_name   = "#{network_bridge} [#{template_name} - Template #{template_id}]"
942
            network_type   = device.backing.network.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) ? "Distributed Port Group" : "Port Group"
943

    
944
            network = find_network(vnpool, network_ref, ccr_ref, template_ref, vcenter_uuid)
945

    
946
            if !network
947
                one_net = ""
948
                one_net << "NAME=\"#{network_name}\"\n"
949
                one_net << "BRIDGE=\"#{network_bridge}\"\n"
950
                one_net << "VN_MAD=\"dummy\"\n"
951
                one_net << "VCENTER_PORTGROUP_TYPE=\"#{network_type}\"\n"
952
                one_net << "VCENTER_NET_REF=\"#{network_ref}\"\n"
953
                one_net << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"
954
                one_net << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
955
                one_net << "VCENTER_TEMPLATE_REF=\"#{template_ref}\"\n"
956
                one_net << "OPENNEBULA_MANAGED=\"NO\"\n"
957
                one_net << "AR=[\n"
958
                one_net << "TYPE=\"ETHER\",\n"
959
                one_net << "SIZE=\"255\"\n"
960
                one_net << "]\n"
961

    
962
                one_vn = OpenNebula::VirtualNetwork.new(OpenNebula::VirtualNetwork.build_xml, one_client)
963
                rc = one_vn.allocate(one_net, cluster_id.to_i)
964
                raise "\n    ERROR! Could not create vnet for template #{template_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
965

    
966
                rc = one_vn.info
967
                raise "\n    ERROR! Could not get network info for template #{template_name}. Reason #{rc.message}" if OpenNebula.is_error?(rc)
968
                STDOUT.puts "--- Network #{one_vn["NAME"]} with ID #{one_vn["ID"]} has been created"
969
                unmanaged[:networks] << one_vn["ID"]
970
            else
971
                unmanaged[:networks] << network["ID"]
972
                STDOUT.puts "--- Network #{network["NAME"]} with ID #{network["ID"]} already exists"
973
            end
974
        end
975
    end
976

    
977
    return unmanaged
978
end
979

    
980
def retrieve_vcenter_clusters(vi_client)
981

    
982
    view = vi_client.vim.serviceContent.viewManager.CreateContainerView({
983
            container: vi_client.vim.rootFolder,
984
            type:      ['ClusterComputeResource'],
985
            recursive: true
986
    })
987

    
988
    pc = vi_client.vim.serviceContent.propertyCollector
989

    
990
    filterSpec = RbVmomi::VIM.PropertyFilterSpec(
991
        :objectSet => [
992
            :obj => view,
993
            :skip => true,
994
            :selectSet => [
995
            RbVmomi::VIM.TraversalSpec(
996
                :name => 'traverseEntities',
997
                :type => 'ContainerView',
998
                :path => 'view',
999
                :skip => false
1000
            )
1001
            ]
1002
        ],
1003
        :propSet => [
1004
            { :type => 'ClusterComputeResource', :pathSet => ['name','host'] }
1005
        ]
1006
    )
1007

    
1008
    result = pc.RetrieveProperties(:specSet => [filterSpec])
1009

    
1010
    clusters = {}
1011
    result.each do |r|
1012
        clusters[r.obj._ref] = r.to_hash if r.obj.is_a?(RbVmomi::VIM::ClusterComputeResource)
1013
    end
1014

    
1015
    view.DestroyView # Destroy the view
1016

    
1017
    return clusters
1018
end
1019

    
1020
def retrieve_vcenter_datastores(vi_client)
1021

    
1022
    view = vi_client.vim.serviceContent.viewManager.CreateContainerView({
1023
            container: vi_client.vim.rootFolder,
1024
            type:      ['Datastore','StoragePod'],
1025
            recursive: true
1026
    })
1027

    
1028
    pc = vi_client.vim.serviceContent.propertyCollector
1029

    
1030
    filterSpec = RbVmomi::VIM.PropertyFilterSpec(
1031
        :objectSet => [
1032
            :obj => view,
1033
            :skip => true,
1034
            :selectSet => [
1035
            RbVmomi::VIM.TraversalSpec(
1036
                :name => 'traverseEntities',
1037
                :type => 'ContainerView',
1038
                :path => 'view',
1039
                :skip => false
1040
            )
1041
            ]
1042
        ],
1043
        :propSet => [
1044
            { :type => 'Datastore', :pathSet => ['name'] },
1045
            { :type => 'StoragePod', :pathSet => ['name'] }
1046
        ]
1047
    )
1048

    
1049
    result = pc.RetrieveProperties(:specSet => [filterSpec])
1050

    
1051
    datastores = {}
1052
    result.each do |r|
1053
        datastores[r.obj._ref] = r.to_hash if r.obj.is_a?(RbVmomi::VIM::Datastore) || r.obj.is_a?(RbVmomi::VIM::StoragePod)
1054
        datastores[r.obj._ref][:ds_type] = r.obj.is_a?(RbVmomi::VIM::Datastore) ? "Datastore" : "StoragePod"
1055
    end
1056

    
1057
    view.DestroyView # Destroy the view
1058

    
1059
    return datastores
1060
end
1061

    
1062
def retrieve_vcenter_networks(vi_client)
1063

    
1064
    view = vi_client.vim.serviceContent.viewManager.CreateContainerView({
1065
        container: vi_client.vim.rootFolder,
1066
        type:      ['Network','DistributedVirtualPortgroup'],
1067
        recursive: true
1068
    })
1069

    
1070
    pc = vi_client.vim.serviceContent.propertyCollector
1071

    
1072
    filterSpec = RbVmomi::VIM.PropertyFilterSpec(
1073
        :objectSet => [
1074
            :obj => view,
1075
            :skip => true,
1076
            :selectSet => [
1077
            RbVmomi::VIM.TraversalSpec(
1078
                :name => 'traverseEntities',
1079
                :type => 'ContainerView',
1080
                :path => 'view',
1081
                :skip => false
1082
            )
1083
            ]
1084
        ],
1085
        :propSet => [
1086
            { :type => 'Network', :pathSet => ['name','host'] },
1087
            { :type => 'DistributedVirtualPortgroup', :pathSet => ['name','host'] }
1088
        ]
1089
    )
1090

    
1091
    result = pc.RetrieveProperties(:specSet => [filterSpec])
1092

    
1093
    networks = {}
1094
    result.each do |r|
1095
        networks[r.obj._ref] = r.to_hash if r.obj.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup) || r.obj.is_a?(RbVmomi::VIM::Network)
1096
        networks[r.obj._ref][:network_type] = r.obj.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup) ? "Distributed Port Group" : "Port Group"
1097
    end
1098

    
1099
    view.DestroyView # Destroy the view
1100

    
1101
    return networks
1102
end
1103

    
1104
def retrieve_vcenter_vms(vi_client)
1105

    
1106
    view = vi_client.vim.serviceContent.viewManager.CreateContainerView({
1107
            container: vi_client.vim.rootFolder,
1108
            type:      ['VirtualMachine'],
1109
            recursive: true
1110
    })
1111

    
1112
    pc = vi_client.vim.serviceContent.propertyCollector
1113

    
1114
    filterSpec = RbVmomi::VIM.PropertyFilterSpec(
1115
        :objectSet => [
1116
            :obj => view,
1117
            :skip => true,
1118
            :selectSet => [
1119
            RbVmomi::VIM.TraversalSpec(
1120
                :name => 'traverseEntities',
1121
                :type => 'ContainerView',
1122
                :path => 'view',
1123
                :skip => false
1124
            )
1125
            ]
1126
        ],
1127
        :propSet => [
1128
            { :type => 'VirtualMachine', :pathSet => ['name','config.template','config.uuid','config.hardware.device', 'config.extraConfig', 'datastore'] }
1129
        ]
1130
    )
1131

    
1132
    result = pc.RetrieveProperties(:specSet => [filterSpec])
1133

    
1134
    vms = {}
1135
    result.each do |r|
1136
        vms[r.obj._ref] = r.to_hash if r.obj.is_a?(RbVmomi::VIM::VirtualMachine)
1137
    end
1138

    
1139
    vmachines = {}
1140
    templates = {}
1141

    
1142
    vms.each do |ref,value|
1143
        if value["config.template"]
1144
            templates[ref] = value
1145
        else
1146
            vmachines[ref] = value
1147
        end
1148
    end
1149

    
1150
    view.DestroyView # Destroy the view
1151

    
1152
    return vmachines, templates
1153
end
1154

    
1155
def select_cluster(vc_clusters, ccr_name, vi_client)
1156
    ccr_ref = nil
1157
    STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
1158
    STDOUT.puts("\nWhich vCenter cluster is represented by OpenNebula \e[96mhost #{ccr_name}?\e[39m\n")
1159
    STDOUT.puts
1160
    index = 0
1161
    ccr_refs = []
1162
    vc_clusters.each do |ref, ccr|
1163
        if ccr_name == ccr["name"]
1164
            item = RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref)
1165

    
1166
            folders = []
1167
            while !item.instance_of? RbVmomi::VIM::Datacenter
1168
                item = item.parent
1169
                if !item.instance_of?(RbVmomi::VIM::Datacenter)
1170
                    if item.name != "host"
1171
                        folders << item.name
1172
                    else
1173
                        folders << ""
1174
                    end
1175
                end
1176
                if item.nil?
1177
                    raise "Could not find the Datacenter for the host"
1178
                end
1179
            end
1180
            datacenter = item
1181
            location   = folders.reverse.join("/")
1182
            location = "/" if location.empty?
1183

    
1184
            ccr_refs << ref
1185
            STDOUT.puts("#{index+1}: #{ccr["name"]} found in #{datacenter.name} datacenter at #{location}")
1186
            index += 1
1187
        end
1188
    end
1189

    
1190
    loop do
1191
        STDOUT.print("\nFrom the list above, please \e[95mpick a number\e[39m in order to specify the cluster: ")
1192
        cluster_index = STDIN.gets.strip.to_i
1193
        next if cluster_index == 0 || cluster_index - 1 < 0 || cluster_index - 1 > ccr_refs.size
1194
        ccr_ref  = ccr_refs[cluster_index-1] rescue nil
1195
        break if ccr_ref
1196
    end
1197

    
1198
    STDOUT.puts
1199
    STDOUT.puts("-" * 80)
1200

    
1201
    ccr_ref
1202
end
1203

    
1204
################################################################################
1205
def add_new_host_attrs(vc_clusters, hpool, one_client, vcenter_ids)
1206

    
1207
    # Get all hosts from pool with VM_MAD=vcenter
1208
    hosts = hpool.retrieve_xmlelements("HOST[VM_MAD=\"vcenter\"]")
1209

    
1210
    hosts.each do |host|
1211
        begin
1212
            # Get OpenNebula host and prepare variables
1213
            one_host        = OpenNebula::Host.new_with_id(host["ID"], one_client)
1214
            rc              = one_host.info
1215
            raise rc.message if OpenNebula.is_error?(rc)
1216
            ccr_name = host["NAME"]
1217
            ccr_ref  = nil
1218
            vi_client       = VCenterDriver::VIClient.new(host["ID"])
1219
            vcenter_uuid    = vi_client.vim.serviceContent.about.instanceUuid
1220
            vcenter_version = vi_client.vim.serviceContent.about.apiVersion
1221

    
1222
            # We try to obtain the Host's moref from vCenter objects
1223
            clusters_with_name = vc_clusters[vcenter_uuid].select {|ref, ccr| ccr["name"] == ccr_name}
1224

    
1225
            # If we cannot obtain the moref we raise an exception
1226
            if clusters_with_name.size == 0
1227
                raise "Host #{ccr_name} could not be updated, cannot find cluster's MOREF"
1228
            end
1229

    
1230
            # If only one moref is found we assign the ref, if many results are
1231
            # found the administrator must select if from a list
1232
            if clusters_with_name.size == 1
1233
                ccr_ref = clusters_with_name.keys.first
1234
            else
1235
                ccr_ref = select_cluster(vc_clusters[vcenter_uuid], ccr_name, vi_client)
1236
            end
1237

    
1238
            # The host's template is updated with the new attributes
1239
            template = ""
1240
            template << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"
1241
            template << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
1242
            template << "VCENTER_VERSION=\"#{vcenter_version}\""
1243
            rc = one_host.update(template, true)
1244
            raise "Host #{ccr_name} could not be updated. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1245
            STDOUT.puts "\nHost \e[96m#{ccr_name}\e[39m got new attributes:\n"
1246
            STDOUT.puts
1247
            STDOUT.puts "--- VCENTER_CCR_REF=#{ccr_ref}\n"
1248
            STDOUT.puts "--- VCENTER_INSTANCE_ID=#{vcenter_uuid}\n"
1249
            STDOUT.puts "--- VCENTER_VERSION=#{vcenter_version}\n"
1250
            STDOUT.puts
1251
            STDOUT.puts "-" * 80
1252
            STDOUT.puts
1253

    
1254
            # We track what hosts have been modified so we can create
1255
            # XML templates later
1256
            vcenter_ids[:host] << one_host["ID"]
1257

    
1258
        rescue Exception => e
1259
            raise e
1260
        ensure
1261
            vi_client.vim.close if vi_client
1262
        end
1263
    end
1264
end
1265

    
1266
################################################################################
1267
def create_new_clusters(vc_clusters, hpool, cpool, one_client)
1268

    
1269
    clusters = {}
1270

    
1271
    # Delete existing files from a previous script launch
1272
    ##if File.exist?("#{TEMP_DIR}/one_migrate_clusters_ids")
1273
    ##    File.delete("#{TEMP_DIR}/one_migrate_clusters_ids")
1274
    ##end
1275

    
1276
    # Get all hosts from pool with VN_MAD="vcenter"
1277
    hosts = hpool.retrieve_xmlelements("HOST[VM_MAD=\"vcenter\"]")
1278

    
1279
    hosts.each do |host|
1280
        begin
1281

    
1282
            # Get OpenNebula host and assign variables
1283
            one_host  = OpenNebula::Host.new_with_id(host["ID"], one_client)
1284
            rc   = one_host.info
1285
            raise rc.message if OpenNebula.is_error?(rc)
1286
            vi_client       = VCenterDriver::VIClient.new(host["ID"])
1287
            vcenter_uuid    = vi_client.vim.serviceContent.about.instanceUuid
1288
            ccr_name = host["NAME"]
1289

    
1290
            # Check if we find the moref for the vCenter cluster
1291
            clusters_with_name = vc_clusters[vcenter_uuid].select {|ref, ccr| ccr["name"] == ccr_name}
1292

    
1293
            if clusters_with_name.size == 0
1294
                raise "Host #{ccr_name} could not be updated, cannot find cluster's MOREF"
1295
            end
1296

    
1297
            # Check if host is assigned to a non default cluster
1298
            if host["CLUSTER_ID"] == "0"
1299

    
1300
                # Check if there's an OpenNebula cluster with the host's name
1301
                one_cluster = find_cluster_by_name(cpool, ccr_name)
1302
                if !one_cluster
1303

    
1304
                    # If the cluster doesn't exits we create a new cluster
1305
                    one_cluster = OpenNebula::Cluster.new(OpenNebula::Cluster.build_xml, one_client)
1306
                    rc = one_cluster.allocate(ccr_name)
1307
                    if OpenNebula.is_error?(rc)
1308
                        STDOUT.puts "    Error creating OpenNebula cluster you should create a cluster by hand with name #{ccr_name} before you upgrade OpenNebula: #{rc.message}\n"
1309
                        next
1310
                    end
1311
                    # We inform that the Cluster has been created
1312
                    STDOUT.puts "OpenNebula Cluster named #{ccr_name} \e[92mhas been created.\e[39m"
1313
                    STDOUT.puts
1314

    
1315
                    # Fetch the cluster info
1316
                    rc = one_cluster.info
1317
                    if OpenNebula.is_error?(rc)
1318
                        STDOUT.puts "    Error Getting information from cluster '#{ccr_name}'. Reason: #{rc.message}\n"
1319
                        next
1320
                    end
1321
                else
1322
                    STDOUT.puts "OpenNebula Cluster #{ccr_name} \e[92malready exists.\e[39m"
1323
                    STDOUT.puts
1324
                end
1325

    
1326
                # Write what cluster ID will be associated to what host ID: host_id:cluster_id
1327
                ##File.open("#{TEMP_DIR}/one_migrate_clusters_ids","a"){|f| f.puts("#{host["ID"]}:#{one_cluster["ID"]}")}
1328

    
1329
                # Store in memory the same information
1330
                clusters[host["ID"]] = one_cluster["ID"]
1331

    
1332
            else
1333
                # Write existing cluster ID
1334
                STDOUT.puts "OpenNebula Cluster #{host["CLUSTER_ID"]} \e[92malready contains Host #{ccr_name}.\e[39m"
1335
                ##File.open("#{TEMP_DIR}/one_migrate_clusters_ids","a"){|f| f.puts("#{host["ID"]}:#{host["CLUSTER_ID"]}")}
1336

    
1337
                clusters[host["ID"]] = host["CLUSTER_ID"]
1338
            end
1339

    
1340
        rescue Exception => e
1341
            raise e
1342
        ensure
1343
            vi_client.vim.close if vi_client
1344
        end
1345
    end
1346

    
1347
    return clusters
1348
end
1349

    
1350
################################################################################
1351
def prepare_host_xml_templates(host_ids, one_clusters, one_client)
1352
    host_ids.each do |host_id|
1353
        # Create XML removing old attributes
1354
        one_host = OpenNebula::Host.new_with_id(host_id, one_client)
1355
        raise rc.message if OpenNebula.is_error?(one_host)
1356
        rc   = one_host.info
1357
        raise rc.message if OpenNebula.is_error?(rc)
1358

    
1359
        # Let's see in which OpenNebula cluster we have to group this host
1360
        if !one_clusters.key?(host_id)
1361
            raise "Could not find the OpenNebula cluster ID that is going to be associated to host ID: #{host_id}"
1362
        end
1363
        cluster_id = one_clusters[host_id]
1364

    
1365
        one_cluster = OpenNebula::Cluster.new_with_id(cluster_id, one_client)
1366
        raise rc.message if OpenNebula.is_error?(one_cluster)
1367
        rc   = one_cluster.info
1368
        raise rc.message if OpenNebula.is_error?(rc)
1369

    
1370
        # We remove old attributes
1371
        xml_doc = Nokogiri::XML(one_host.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
1372
        xml_doc.root.xpath("TEMPLATE/PUBLIC_CLOUD").remove
1373
        xml_doc.root.xpath("TEMPLATE/VCENTER_DATASTORE").remove
1374
        xml_doc.root.xpath("TEMPLATE/RESOURCE_POOL").remove
1375

    
1376
        # We have to assign the host to the right cluster
1377
        xml_cluster_id  = xml_doc.root.at_xpath("CLUSTER_ID")
1378
        xml_cluster_id.content = cluster_id
1379
        xml_cluster  = xml_doc.root.at_xpath("CLUSTER")
1380
        xml_cluster.content = one_cluster["NAME"]
1381

    
1382
        STDOUT.puts
1383
        STDOUT.puts "New XML file #{TEMP_DIR}/one_migrate_host_#{host_id} for host \e[96m#{one_host["NAME"]}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
1384
        File.open("#{TEMP_DIR}/one_migrate_host_#{host_id}","w"){|f| f.puts(xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<"))}
1385
    end
1386
end
1387

    
1388
################################################################################
1389
def inspect_datastores(vc_datastores, vc_clusters, one_clusters, dspool, hpool, one_client, vcenter_ids)
1390

    
1391
    # Retrive datastores with TM_MAD="vcenter"
1392
    datastores = dspool.retrieve_xmlelements("DATASTORE[TM_MAD=\"vcenter\"]")
1393

    
1394
    # Remove previous system datastores created earlier by this script to
1395
    # avoid conflicts. Only those without VCENTER_CLUSTER attribute are removed
1396
    datastores.each do |datastore|
1397
        if datastore["TEMPLATE/TYPE"] == "SYSTEM_DS" && datastore["TEMPLATE/VCENTER_CLUSTER"].nil?
1398
            one_ds  = OpenNebula::Datastore.new_with_id(datastore["ID"], one_client)
1399
            one_ds.delete
1400
        end
1401
    end
1402

    
1403
    STDOUT.puts
1404

    
1405
    # Refresh dspool and retrieve datastores again
1406
    rc = dspool.info
1407
    raise "Datastore pool info could not be retrieved. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1408

    
1409
    # Inspect existing vcenter datastores
1410
    datastores = dspool.retrieve_xmlelements("DATASTORE[TM_MAD=\"vcenter\"]")
1411
    datastores.each do |datastore|
1412
        begin
1413
            # Get OpenNebula datastore and retrieve variables
1414
            ds_id   = datastore["ID"]
1415
            one_ds  = OpenNebula::Datastore.new_with_id(datastore["ID"], one_client)
1416
            rc      = one_ds.info
1417
            raise rc.message if OpenNebula.is_error?(rc)
1418
            ds_name = one_ds["NAME"]
1419
            ccr_name = one_ds["TEMPLATE/VCENTER_CLUSTER"]
1420
            next if !ccr_name # If VCENTER_CLUSTER doesn't exist it's not usable
1421

    
1422
            # Get cluster's host from its name stored in VCENTER_CLUSTER
1423
            hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
1424
            if hosts.empty?
1425
                raise "Could not find OpenNebula host associated to VCENTER_CLUSTER"
1426
            end
1427

    
1428
            # Check if host already has the ccr moref
1429
            ccr_ref = hosts.first["TEMPLATE/VCENTER_CCR_REF"]
1430
            if ccr_ref.nil?
1431
                raise "Datastore #{ds_name} could not be updated, cannot find cluster's MOREF"
1432
            end
1433

    
1434
            # Get OpenNebula host's id and create a Rbvmomi connection
1435
            host_id = hosts.first["ID"]
1436
            vi_client       = VCenterDriver::VIClient.new(host_id)
1437
            vcenter_uuid    = vi_client.vim.serviceContent.about.instanceUuid
1438
            vcenter_name    = vi_client.host
1439

    
1440
            # Datastores require now vcenter credentials
1441
            vcenter_user = hosts.first["TEMPLATE/VCENTER_USER"]
1442
            vcenter_pass = hosts.first["TEMPLATE/VCENTER_PASSWORD"]
1443
            vcenter_host = hosts.first["TEMPLATE/VCENTER_HOST"]
1444

    
1445
            # Check if we can find the datastore in objects retrieved from vCenter
1446
            datastores_with_name = vc_datastores[vcenter_uuid].select {|ref, ds| ds["name"] == ds_name}
1447
            if datastores_with_name.empty?
1448
                raise "Could not find datastore in vcenter by its name #{ds_name}"
1449
            end
1450

    
1451
            ds_ref  = nil
1452
            ds_type = nil
1453
            dc_ref  = nil
1454
            dc_name = nil
1455

    
1456
            # If we find only one vCenter datastore for that name we assign it
1457
            # otherwise the administrator should select one from the list
1458
            # We need to extract the datacenter ref and name as they are now
1459
            # required attributes.
1460
            if datastores_with_name.size == 1
1461
                vc_datastores[vcenter_uuid].each do |ref, ds|
1462
                    if ds["name"] == ds_name
1463
                        ds_ref = ref
1464
                        ds_type = ds[:ds_type]
1465

    
1466
                        item = nil
1467
                        # Check if Datastore is a StoragePod
1468
                        if ds[:ds_type] == "Datastore"
1469
                            item = RbVmomi::VIM::Datastore.new(vi_client.vim, ref)
1470
                        else
1471
                            item = RbVmomi::VIM::StoragePod.new(vi_client.vim, ref)
1472
                        end
1473

    
1474
                        # We try to get the datacenter object where this datastore is located
1475
                        while !item.instance_of? RbVmomi::VIM::Datacenter
1476
                            item = item.parent
1477
                            if item.nil?
1478
                                raise "Could not find the Datacenter for the datastore"
1479
                            end
1480
                        end
1481
                        dc_ref  = item._ref
1482
                        dc_name = item.name
1483
                        break
1484
                    end
1485
                end
1486
            else
1487
                # Select the datastore from a list of possible matches
1488
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
1489
                STDOUT.puts("\nWhich vCenter datastore is represented by OpenNebula \e[96mdatastore #{ds_name}?\n\e[39m")
1490
                STDOUT.puts
1491
                index = 0
1492
                ds_info  = []
1493
                vc_datastores[vcenter_uuid].each do |ref, ds|
1494
                    if ds_name == ds["name"]
1495
                        # Discriminate if it's a datastore or a Storage Pod
1496
                        if ds[:ds_type] == "Datastore"
1497
                            item = RbVmomi::VIM::Datastore.new(vi_client.vim, ref)
1498
                        else
1499
                            item = RbVmomi::VIM::StoragePod.new(vi_client.vim, ref)
1500
                        end
1501
                        # We need the datacenter
1502
                        while !item.instance_of? RbVmomi::VIM::Datacenter
1503
                            item = item.parent
1504
                            if item.nil?
1505
                                raise "Could not find the Datacenter for the datastore"
1506
                            end
1507
                        end
1508
                        datacenter = item
1509

    
1510
                        # Prepare a hash with the information we need
1511
                        info = {}
1512
                        info[:ref]     = ref
1513
                        info[:ds_type] = ds[:ds_type]
1514
                        info[:dc_name] = datacenter.name
1515
                        info[:dc_ref] = datacenter._ref
1516
                        ds_info << info
1517
                        STDOUT.puts("#{index+1}: Datastore #{ds["name"]} in #{datacenter.name}")
1518
                        index += 1
1519
                    end
1520
                end
1521

    
1522
                # Loop until the admin user chooses the right datastore
1523
                loop do
1524
                    STDOUT.print("\nFrom the list above, please \e[95mpick one number\e[39m in order to specify the datastore: ")
1525
                    ds_index = STDIN.gets.strip.to_i
1526
                    next if ds_index == 0 || ds_index - 1 < 0 || ds_index - 1 > ds_info.size
1527
                    ds_ref  = ds_info[ds_index-1][:ref] rescue nil
1528
                    ds_type = ds_info[ds_index-1][:ds_type] rescue nil
1529
                    dc_name = ds_info[ds_index-1][:dc_name] rescue nil
1530
                    dc_ref  = ds_info[ds_index-1][:dc_ref] rescue nil
1531
                    break if ds_ref
1532
                end
1533

    
1534
                STDOUT.puts
1535
                STDOUT.puts("-" * 80)
1536
                STDOUT.puts
1537
            end
1538

    
1539
            # Raise and exception if we cannot find the datastore's moref
1540
            if ds_ref.nil?
1541
                raise "Datastore #{ds_name} could not be updated, cannot find datastore's MOREF"
1542
            end
1543

    
1544
            # Prepare new datastore attributes
1545
            template = ""
1546
            template << "VCENTER_DS_REF=\"#{ds_ref}\"\n"
1547
            template << "VCENTER_DS_NAME=\"#{ds_name}\"\n"
1548
            template << "VCENTER_DC_REF=\"#{dc_ref}\"\n"
1549
            template << "VCENTER_DC_NAME=\"#{dc_name}\"\n"
1550
            template << "VCENTER_HOST=\"#{vcenter_host}\"\n"
1551
            template << "VCENTER_USER=\"#{vcenter_user}\"\n"
1552
            template << "VCENTER_PASSWORD=\"#{vcenter_pass}\"\n"
1553
            template << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
1554

    
1555
            # Update the template
1556
            rc = one_ds.update(template, true)
1557
            raise "Datastore #{ds_name} could not be updated. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1558

    
1559
            # Inform what attributes have been added
1560
            STDOUT.puts "Datastore \e[96m#{ds_name}\e[39m got new attributes:\n"
1561
            STDOUT.puts
1562
            STDOUT.puts "--- VCENTER_DS_REF=\"#{ds_ref}\"\n"
1563
            STDOUT.puts "--- VCENTER_DS_NAME=\"#{ds_name}\"\n"
1564
            STDOUT.puts "--- VCENTER_DC_REF=\"#{dc_ref}\"\n"
1565
            STDOUT.puts "--- VCENTER_DC_NAME=\"#{dc_name}\"\n"
1566
            STDOUT.puts "--- VCENTER_HOST=\"#{vcenter_host}\"\n"
1567
            STDOUT.puts "--- VCENTER_USER=\"#{vcenter_user}\"\n"
1568
            STDOUT.puts "--- VCENTER_PASSWORD=\"#{vcenter_pass}\"\n"
1569
            STDOUT.puts "--- VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
1570

    
1571
            STDOUT.puts
1572

    
1573
            # Update datastore information
1574
            rc = one_ds.info
1575
            raise "Datastore info #{ds_name} could not be retrieved. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1576

    
1577
            # Let's see in which OpenNebula cluster we have to group this datastore
1578
            if !one_clusters.key?(host_id)
1579
                raise "Could not find the OpenNebula cluster ID that is going to be associated to host ID: #{host_id}"
1580
            end
1581
            cluster_id = one_clusters[host_id]
1582

    
1583
            # Add IMAGE datastore to OpenNebula cluster if it hasn't been assigned previously
1584
            cluster_ids = one_ds.retrieve_xmlelements("CLUSTERS")
1585
            found_cluster_ids = cluster_ids.select { |cluster| cluster["ID"] == cluster_id }
1586
            if found_cluster_ids.empty?
1587
                one_cluster  = OpenNebula::Cluster.new_with_id(cluster_id, one_client)
1588
                rc = one_cluster.adddatastore(ds_id.to_i)
1589
                if OpenNebula.is_error?(rc)
1590
                    raise "Datastore #{ds_name} could not be assigned to cluster ID: #{cluster_id} you should assign this datastore to that cluster by hand once this script finishes. Reason #{rc.message}"
1591
                else
1592
                    STDOUT.puts "Datastore \e[96m#{ds_name}\e[39m has been assigned to cluster ID: #{cluster_id}."
1593
                    STDOUT.puts
1594
                end
1595
            end
1596

    
1597
            # Check if SYSTEM datastore was not created before
1598
            # and create SYSTEM_DS associated to the existing IMAGE_DS and add it
1599
            # to the right OpenNebula cluster
1600
            if ds_type == "Datastore"
1601
                create_system_ds(ds_name, ds_ref, vcenter_name, vcenter_uuid, dc_name, dc_ref, one_client, vcenter_host, vcenter_user, vcenter_pass, cluster_id)
1602
            end
1603

    
1604
            STDOUT.puts
1605
            STDOUT.puts "-" * 80
1606
            STDOUT.puts
1607

    
1608
            # We track what datastores have been modified so we can create
1609
            # XML templates later
1610
            vcenter_ids[:ds] << one_ds["ID"]
1611

    
1612
        rescue Exception => e
1613
            raise e
1614
        ensure
1615
            vi_client.vim.close if vi_client
1616
        end
1617
    end
1618
end
1619

    
1620
################################################################################
1621
def prepare_ds_xml_templates(ds_ids, one_client)
1622

    
1623
    ds_ids.each do |ds_id|
1624
        # Create XML removing old attributes
1625
        one_ds = OpenNebula::Datastore.new_with_id(ds_id, one_client)
1626
        rc   = one_ds.info
1627
        raise rc.message if OpenNebula.is_error?(rc)
1628
        xml_doc = Nokogiri::XML(one_ds.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
1629
        xml_doc.root.xpath("TEMPLATE/VCENTER_CLUSTER").remove
1630

    
1631
        # Replace CLONE_TARGET from NONE to SYSTEM
1632
        xml_template = xml_doc.root.at_xpath("TEMPLATE")
1633
        clone_target = xml_template.xpath("CLONE_TARGET").text
1634
        if !clone_target.empty?
1635
            xml_template.xpath("CLONE_TARGET").remove
1636
            xml_template.add_child(xml_doc.create_element("CLONE_TARGET")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"SYSTEM"))
1637
        end
1638

    
1639
        File.open("#{TEMP_DIR}/one_migrate_ds_#{one_ds["ID"]}","w"){|f| f.puts(xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<"))}
1640
        STDOUT.puts
1641
        STDOUT.puts "New XML file #{TEMP_DIR}/one_migrate_ds_#{one_ds["ID"]} for datastore \e[96m#{one_ds["NAME"]}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
1642
    end
1643
end
1644

    
1645
################################################################################
1646
def inspect_networks(vc_networks, vc_clusters, one_clusters, vnpool, hpool, one_client, vcenter_ids)
1647

    
1648
    # Retrive virtual networks that have the VCENTER_TYPE attribute
1649
    vnets = vnpool.retrieve_xmlelements("VNET[TEMPLATE/VCENTER_TYPE=\"Port Group\" or TEMPLATE/VCENTER_TYPE=\"Distributed Port Group\"]")
1650

    
1651
    # For each port group...
1652
    vnets.each do |vnet|
1653

    
1654
        begin
1655
            # Get OpenNebula's virtual network and retrieve some variables
1656
            one_vnet = OpenNebula::VirtualNetwork.new_with_id(vnet["ID"], one_client)
1657
            rc   = one_vnet.info
1658
            raise rc.message if OpenNebula.is_error?(rc)
1659
            vnet_id      = vnet["ID"]
1660
            vnet_name    = vnet["NAME"]
1661
            vnet_bridge  = vnet["TEMPLATE/BRIDGE"]
1662
            vnet_pg_type = vnet["TEMPLATE/VCENTER_TYPE"]
1663

    
1664
            # Try to get cluster associated to this network from imported name
1665
            # OpenNebula creates a vnet name with portgroup name - cluster name
1666
            ccr_name = vnet_name.split(" - ")[-1] rescue nil
1667

    
1668
            # Let's see if we can find the cluster name from the vnet name
1669
            if ccr_name
1670
                hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
1671
                ccr_name = nil if hosts.empty?
1672
            end
1673

    
1674
            # If cluster name could not be determined, user action required
1675
            # The administrator must choose what cluster is associate with the vnet
1676
            if !ccr_name
1677
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
1678
                STDOUT.puts("\nWhich vCenter cluster is associated with OpenNebula \e[96mvnet #{vnet_name}?\n\e[39m")
1679

    
1680
                ccr_names = []
1681
                hpool.each_with_index do |host, index|
1682
                    STDOUT.puts("#{index+1}: #{host["NAME"]} in #{host["TEMPLATE/VCENTER_HOST"]}")
1683
                    ccr_names << host["NAME"]
1684
                end
1685

    
1686
                STDOUT.puts("#{ccr_names.size+1}: None of the above.")
1687

    
1688
                loop do
1689
                    STDOUT.print("\nFrom the list above, please pick one number in order to specify the cluster: ")
1690
                    cluster_index = STDIN.gets.strip.to_i
1691
                    next if cluster_index == 0 || cluster_index - 1 < 0 || cluster_index - 1 > ccr_names.size+1
1692
                    ccr_name  = ccr_names[cluster_index-1] rescue nil
1693
                    break
1694
                end
1695

    
1696
                STDOUT.puts
1697
                STDOUT.puts("-" * 80)
1698
                STDOUT.puts
1699
            end
1700

    
1701
            # If we could not determine what cluster name is associated to the network
1702
            # raise an exception.
1703
            if !ccr_name
1704
                raise "We could not find the host name associated to vnet #{vnet_name}\n"\
1705
                      "You may have to import the vCenter cluster using the onevcenter tool."
1706
            end
1707

    
1708
            # Get cluster's ccr ref and host id from its name
1709
            hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
1710
            ccr_ref = hosts.first["TEMPLATE/VCENTER_CCR_REF"]
1711
            if ccr_ref.nil?
1712
                raise "Vnet #{vnet_name} could not be updated, cannot find cluster's MOREF"
1713
            end
1714
            host_id      = hosts.first["ID"]
1715
            vi_client    = VCenterDriver::VIClient.new(host_id)
1716
            vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
1717

    
1718
            # Get vnet MOREF from vcenter info and the port group's name
1719
            vnets_with_name = vc_networks[vcenter_uuid].select {|ref, net| net["name"] == vnet_bridge}
1720
            if vnets_with_name.empty?
1721
                raise "Could not find vnet in vcenter by its name #{vnet_name}"
1722
            end
1723

    
1724
            # Check how many refs we've found for that port group name
1725
            vnet_ref  = nil
1726

    
1727
            if vnets_with_name.size == 1
1728
                vnet_ref = vnets_with_name.keys.first
1729
            else
1730
                # If there are many possible morefs the admin must select one from a list
1731
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
1732
                STDOUT.puts("\nWhich vCenter port group is represented by OpenNebula \e[96mvnet #{vnet_name}?\e[39m\n")
1733
                STDOUT.puts
1734
                index = 0
1735
                vnet_refs  = []
1736
                vc_networks[vcenter_uuid].each do |ref, net|
1737
                    if net["name"] == vnet_bridge
1738
                        item = RbVmomi::VIM::Network.new(vi_client.vim, ref)
1739

    
1740
                        # We need the datatacenter info associated to the port group
1741
                        while !item.instance_of? RbVmomi::VIM::Datacenter
1742
                            item = item.parent
1743
                            if item.nil?
1744
                                raise "Could not find the Datacenter for the datastore"
1745
                            end
1746
                        end
1747
                        datacenter = item
1748

    
1749
                        vnet_refs << ref
1750
                        STDOUT.puts("#{index+1}: Virtual Network #{vnet_name} in #{datacenter.name}")
1751
                        index += 1
1752
                    end
1753
                end
1754

    
1755
                # Loop until the administrator selects a vnet
1756
                loop do
1757
                    STDOUT.print("\nFrom the list above, please \e[95mpick one number\e[39m in order to specify the vnet: ")
1758
                    vnet_index = STDIN.gets.strip.to_i
1759
                    next if vnet_index == 0 || vnet_index - 1 < 0 || vnet_index - 1 > vnet_refs.size
1760
                    vnet_ref  = vnet_refs[vnet_index-1] rescue nil
1761
                    break if vnet_ref
1762
                end
1763

    
1764
                STDOUT.puts
1765
                STDOUT.puts("-" * 80)
1766
            end
1767

    
1768
            STDOUT.puts
1769

    
1770
            raise "Vnet #{vnet_name} could not be updated, cannot find vnet's MOREF" if vnet_ref.nil?
1771

    
1772
            # Prepare vnet's template attributes
1773
            template = ""
1774
            template << "VCENTER_NET_REF=\"#{vnet_ref}\"\n"
1775
            template << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
1776
            template << "VCENTER_PORTGROUP_TYPE=\"#{vnet_pg_type}\"\n"
1777
            template << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"
1778

    
1779
            # Try to update the vnet template
1780
            rc = one_vnet.update(template, true)
1781
            raise "Vnet #{vnet_name} could not be updated. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1782

    
1783
            # Inform what attributes have been added
1784
            STDOUT.puts "\nVnet \e[96m#{vnet_name}\e[39m got new attributes:\n"
1785
            STDOUT.puts "--- VCENTER_NET_REF=#{vnet_ref}\n"
1786
            STDOUT.puts "--- VCENTER_INSTANCE_ID=#{vcenter_uuid}\n"
1787
            STDOUT.puts "--- VCENTER_PORTGROUP_TYPE=#{vnet_pg_type}\n"
1788
            STDOUT.puts "--- VCENTER_CCR_REF=#{ccr_ref}\n"
1789
            STDOUT.puts
1790

    
1791
            # Let's see in which OpenNebula cluster we have to group this vnet
1792
            if !one_clusters.key?(host_id)
1793
                raise "Could not find the OpenNebula cluster ID that is going to be associated to host ID: #{host_id}"
1794
            end
1795

    
1796
            # Add vnet to OpenNebula cluster
1797
            # Check if the vnet is already assigned to the right cluster
1798
            cluster_id        = one_clusters[host_id]
1799
            cluster_ids       = one_vnet.retrieve_xmlelements("CLUSTERS")
1800
            found_cluster_ids = cluster_ids.select { |cluster| cluster["ID"] == cluster_id }
1801

    
1802
            if found_cluster_ids.empty?
1803
                one_cluster  = OpenNebula::Cluster.new_with_id(cluster_id, one_client)
1804
                rc = one_cluster.addvnet(vnet_id.to_i)
1805
                if OpenNebula.is_error?(rc)
1806
                    raise "Network #{vnet_name} could not be assigned to cluster ID: #{cluster_id} you should assign this virtual network to that cluster by hand once this script finishes. Reason #{rc.message}"
1807
                else
1808
                    STDOUT.puts "Vnet \e[96m#{vnet_name}\e[39m has been assigned to cluster ID: #{cluster_id}."
1809
                end
1810
            end
1811

    
1812
            STDOUT.puts
1813
            STDOUT.puts "-" * 80
1814
            STDOUT.puts
1815

    
1816
            # We track what vcenter_ids have been modified so we can create
1817
            # XML templates later
1818
            vcenter_ids[:vnet] << one_vnet["ID"]
1819

    
1820
        rescue Exception => e
1821
            raise e
1822
        ensure
1823
            vi_client.vim.close if vi_client
1824
        end
1825
    end
1826
end
1827

    
1828
################################################################################
1829
def prepare_vnet_xml_templates(vnet_ids, one_client)
1830
    vnet_ids.each do |vnet_id|
1831
        # Create XML removing old attributes
1832
        one_vnet = OpenNebula::VirtualNetwork.new_with_id(vnet_id, one_client)
1833
        rc   = one_vnet.info
1834
        raise rc.message if OpenNebula.is_error?(rc)
1835
        xml_doc = Nokogiri::XML(one_vnet.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
1836
        xml_doc.root.xpath("TEMPLATE/VCENTER_TYPE").remove
1837
        File.open("#{TEMP_DIR}/one_migrate_vnet_#{vnet_id}","w"){|f| f.puts(xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<"))}
1838
        STDOUT.puts
1839
        STDOUT.puts "New XML file #{TEMP_DIR}/one_migrate_vnet_#{vnet_id} for vnet \e[96m#{one_vnet["NAME"]}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
1840
    end
1841
end
1842

    
1843
################################################################################
1844
def add_new_image_attrs(ipool, one_client, vcenter_ids)
1845

    
1846
    # Retrieve images with VCENTER_IMPORTED="YES"
1847
    imported_images = ipool.retrieve_xmlelements("IMAGE[TEMPLATE/VCENTER_IMPORTED=\"YES\"]")
1848

    
1849
    # Remove previous imported images so we regenerate them again
1850
    imported_images.each do |image|
1851
        one_image  = OpenNebula::Image.new_with_id(image["ID"], one_client)
1852
        one_image.delete
1853

    
1854
        loop do
1855
            rc = one_image.info
1856
            break if OpenNebula.is_error?(rc)
1857
        end
1858
    end
1859

    
1860
    STDOUT.puts
1861

    
1862
    # Refresh pool
1863
    rc = ipool.info_all
1864
    raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
1865

    
1866
    # Loop through existing images
1867
    ipool.each do |image|
1868
        # Initialize some variables
1869
        image_name = image["NAME"]
1870
        template = ""
1871
        adapter_type = nil
1872
        disk_type    = nil
1873

    
1874
        # Get images
1875
        one_image = OpenNebula::Image.new_with_id(image["ID"], one_client)
1876
        rc   = one_image.info
1877
        raise rc.message if OpenNebula.is_error?(rc)
1878

    
1879
        # Create VCENTER_ADAPTER_TYPE attribute
1880
        adapter_type = one_image["TEMPLATE/ADAPTER_TYPE"]
1881
        template << "VCENTER_ADAPTER_TYPE=\"#{adapter_type}\"\n" if adapter_type
1882

    
1883
        # Check if DISK_TYPE is one of those used by vcenter as this attribute
1884
        # is shared with KVM images
1885
        disk_type = one_image["TEMPLATE/DISK_TYPE"]
1886
        disk_types = ["delta","eagerZeroedThick","flatMonolithic",
1887
                      "preallocated","raw","rdm","rdmp","seSparse",
1888
                      "sparse2Gb","sparseMonolithic","thick","thick2Gb","thin"]
1889
        if disk_type && disk_types.include?(disk_type)
1890
            template << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n"
1891
        end
1892

    
1893
        # Update image's template
1894
        if !template.empty?
1895
            rc = one_image.update(template, true)
1896
            raise "Image #{image_name} could not be updated. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1897

    
1898
            # Inform about what attributes have been added
1899
            STDOUT.puts "\nImage \e[96m#{image_name}\e[39m got new attributes:\n"
1900
            STDOUT.puts
1901
            STDOUT.puts "--- VCENTER_DISK_TYPE=#{disk_type}\n"
1902
            STDOUT.puts "--- VCENTER_ADAPTER_TYPE=#{adapter_type}\n"
1903
            STDOUT.puts
1904

    
1905
            STDOUT.puts
1906
            STDOUT.puts "-" * 80
1907
            STDOUT.puts
1908

    
1909
            # We track what vcenter_ids have been modified so we can create
1910
            # XML templates later
1911
            vcenter_ids[:image] << one_image["ID"]
1912
        end
1913
    end
1914
end
1915

    
1916
################################################################################
1917
def prepare_image_xml_templates(image_ids, hpool, one_client)
1918
    image_ids.each do |image_id|
1919
        begin
1920
            one_image = OpenNebula::Image.new_with_id(image_id, one_client)
1921
            rc   = one_image.info
1922
            raise rc.message if OpenNebula.is_error?(rc)
1923

    
1924
            # Remove old attributes
1925
            xml_doc = Nokogiri::XML(one_image.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
1926
            xml_doc.root.xpath("TEMPLATE/ADAPTER_TYPE").remove
1927
            xml_doc.root.xpath("TEMPLATE/DISK_TYPE").remove
1928

    
1929
            # Update image's size
1930
            one_ds = OpenNebula::Datastore.new_with_id(one_image["DATASTORE_ID"], one_client)
1931
            rc   = one_ds.info
1932
            raise rc.message if OpenNebula.is_error?(rc)
1933
            image_source = one_image["SOURCE"]
1934
            ds_ref  = one_ds["TEMPLATE/VCENTER_DS_REF"]
1935

    
1936
            # Get Datastore's cluster name
1937
            ccr_name = one_ds["TEMPLATE/VCENTER_CLUSTER"]
1938
            next if !ccr_name
1939

    
1940
            # Get cluster's host from its name
1941
            hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{ccr_name}\"]")
1942
            if hosts.empty?
1943
                raise "Could not find OpenNebula host associated to VCENTER_CLUSTER"
1944
            end
1945
            host_id = hosts.first["ID"]
1946

    
1947
            vi_client = VCenterDriver::VIClient.new(host_id)
1948
            disk_size = get_image_size(RbVmomi::VIM::Datastore.new(vi_client.vim, ds_ref), image_source)
1949
            xml_size  = xml_doc.root.at_xpath("SIZE")
1950
            xml_size.content = disk_size
1951

    
1952
            File.open("#{TEMP_DIR}/one_migrate_image_#{image_id}","w"){|f| f.puts(xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<"))}
1953

    
1954
            STDOUT.puts
1955
            STDOUT.puts "New XML file #{TEMP_DIR}/one_migrate_image_#{image_id} for image \e[96m#{one_image["NAME"]}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
1956

    
1957
        rescue Exception => e
1958
            raise e
1959
        ensure
1960
            vi_client.vim.close if vi_client
1961
        end
1962
    end
1963
end
1964

    
1965
################################################################################
1966
def inspect_templates(vc_templates, vc_clusters, one_clusters, tpool, ipool, vnpool, dspool, hpool, one_client, vcenter_ids)
1967
    # Retrieve all OpenNebula templates associated with PUBLIC_CLOUD=vcenter
1968
    templates = tpool.retrieve_xmlelements("VMTEMPLATE[TEMPLATE/PUBLIC_CLOUD/TYPE=\"vcenter\"]")
1969

    
1970
    templates.each do |template|
1971
        begin
1972
            # Refresh pools
1973
            rc = vnpool.info_all
1974
            raise "\n    ERROR! Could not update vnpool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1975
            rc = ipool.info_all
1976
            raise "\n    ERROR! Could not update ipool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1977
            rc = dspool.info
1978
            raise "\n    ERROR! Could not update dspool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
1979

    
1980
            # Get some variables
1981
            ccr_ref      = nil
1982
            vcenter_uuid = nil
1983
            host_id      = nil
1984

    
1985
            template_name    = template["NAME"]
1986
            template_uuid    = template["TEMPLATE/PUBLIC_CLOUD/VM_TEMPLATE"]
1987
            template_ref     = template["TEMPLATE/PUBLIC_CLOUD/VCENTER_REF"]
1988
            template_cluster = template["TEMPLATE/PUBLIC_CLOUD/HOST"]
1989
            template_rp      = template["TEMPLATE/RESOURCE_POOL"]
1990
            template_user_rp = template["TEMPLATE/USER_INPUTS/RESOURCE_POOL"]
1991

    
1992
            # Check if we can find what vCenter cluster is associated with the
1993
            # Template
1994
            if template_cluster
1995
                # Does a host with the template host name exist?
1996
                hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{template_cluster}\"]")
1997
                if hosts.empty?
1998
                    template_cluster = nil
1999
                else
2000
                    # Check if we can get the morefs from the OpenNebula host
2001
                    ccr_ref      = hosts.first["TEMPLATE/VCENTER_CCR_REF"]
2002
                    vcenter_uuid = hosts.first["TEMPLATE/VCENTER_INSTANCE_ID"]
2003
                    host_id      = hosts.first["ID"]
2004
                    vcenter_user = hosts.first["TEMPLATE/VCENTER_USER"]
2005
                    vcenter_pass = hosts.first["TEMPLATE/VCENTER_PASSWORD"]
2006
                    vcenter_host = hosts.first["TEMPLATE/VCENTER_HOST"]
2007

    
2008
                    template_cluster = nil if !ccr_ref || !vcenter_uuid
2009
                end
2010
            end
2011

    
2012
            # As we don't know which vCenter cluster is associated with the template
2013
            # The administrator must select one from a list
2014
            if !template_cluster
2015
                hpool_vcenter = hpool.select{|h| h["VM_MAD"] == "vcenter"}
2016

    
2017
                if hpool_vcenter.count == 1
2018
                    template_cluster = hpool_vcenter.first["NAME"]
2019
                else
2020
                    STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2021
                    STDOUT.puts("\nWhich vCenter cluster is associated with OpenNebula \e[96mtemplate #{template_name}?\n\e[39m")
2022
                    STDOUT.puts
2023

    
2024
                    ccr_names = []
2025
                    hpool_vcenter.each_with_index do |host, index|
2026
                        STDOUT.puts("#{index+1}: #{host["NAME"]} in #{host["TEMPLATE/VCENTER_HOST"]}")
2027
                        ccr_names << host["NAME"]
2028
                    end
2029

    
2030
                    STDOUT.puts("#{ccr_names.size+1}: None of the above.")
2031

    
2032
                    loop do
2033
                        STDOUT.print("\nFrom the list above, please \e[95mpick one number\e[39m in order to specify the cluster: ")
2034
                        cluster_index = STDIN.gets.strip.to_i
2035
                        next if cluster_index == 0 || cluster_index - 1 < 0 || cluster_index > ccr_names.size+1
2036
                        template_cluster  = ccr_names[cluster_index-1] rescue nil
2037
                        break
2038
                    end
2039

    
2040
                    STDOUT.puts
2041
                    STDOUT.puts "-" * 80
2042
                    STDOUT.puts
2043
                end
2044

    
2045
                if !template_cluster
2046
                    raise "We could not find the host name associated to template #{template_name}\n"\
2047
                          "You may have to import the OpenNebula host first using onevcenter tool."
2048
                end
2049

    
2050
                # Get host attributes from the name of the cluster associated
2051
                # to the template
2052
                hosts = hpool.retrieve_xmlelements("HOST[NAME=\"#{template_cluster}\"]")
2053

    
2054
                ccr_ref      = hosts.first["TEMPLATE/VCENTER_CCR_REF"]
2055
                vcenter_uuid = hosts.first["TEMPLATE/VCENTER_INSTANCE_ID"]
2056
                host_id      = hosts.first["ID"]
2057
                vcenter_user = hosts.first["TEMPLATE/VCENTER_USER"]
2058
                vcenter_pass = hosts.first["TEMPLATE/VCENTER_PASSWORD"]
2059
                vcenter_host = hosts.first["TEMPLATE/VCENTER_HOST"]
2060
            end
2061

    
2062
            if ccr_ref.nil? || vcenter_uuid.nil?
2063
                raise "Template #{template_name} could not be updated, cannot find cluster's MOREF: '#{ccr_ref}'" \
2064
                      ", or vcenter uuid: '#{vcenter_uuid}'. "
2065
            end
2066

    
2067
            # Create Rbvmomi connection
2068
            vi_client    = VCenterDriver::VIClient.new(host_id)
2069
            vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
2070

    
2071
            # We try to check if the template's moref found inside the XML template
2072
            # is found in the templates retrieved from vcenter only once
2073
            if template_ref
2074

    
2075
                templates_found = vc_templates[vcenter_uuid].select do |ref, value|
2076
                    template_ref == ref
2077
                end
2078

    
2079
                if templates_found.size != 1
2080
                    template_ref = nil
2081
                end
2082
            end
2083

    
2084
            # Try to get moref using the templates uuid. Note that that uuid
2085
            # is not unique
2086
            templates_same_uuid = {}
2087
            if !template_ref && template_uuid
2088
                templates_found = 0
2089
                vc_templates[vcenter_uuid].each do |ref, value|
2090
                    if value["config.uuid"] == template_uuid
2091
                        templates_found += 1
2092
                        templates_same_uuid[ref] = value
2093
                        if templates_found > 1
2094
                            template_ref = nil
2095
                        else
2096
                            template_ref = ref
2097
                        end
2098
                    end
2099
                end
2100
            end
2101

    
2102
            # If we could not found the template moref the administrator has to help us
2103
            if !template_ref
2104
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2105
                STDOUT.puts("\nWhich vCenter template is associated with OpenNebula \e[96mtemplate #{template_name}?\n\e[39m")
2106
                STDOUT.puts
2107
                index = 0
2108
                template_refs  = []
2109

    
2110
                if templates_same_uuid.length > 1
2111
                    # Choose only between those that have the same UUID
2112
                    templates_list = templates_same_uuid
2113
                else
2114
                    templates_list = vc_templates[vcenter_uuid]
2115
                end
2116

    
2117
                templates_list.each do |ref, t|
2118
                    item = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2119

    
2120
                    folders = []
2121
                    while !item.instance_of? RbVmomi::VIM::Datacenter
2122
                        item = item.parent
2123
                        if !item.instance_of?(RbVmomi::VIM::Datacenter)
2124
                            if item.name != "vm"
2125
                                folders << item.name
2126
                            else
2127
                                folders << ""
2128
                            end
2129
                        end
2130
                        if item.nil?
2131
                            raise "Could not find the Datacenter for the template"
2132
                        end
2133
                    end
2134
                    datacenter = item
2135
                    location   = folders.reverse.join("/")
2136
                    location = "/" if location.empty?
2137

    
2138
                    template_refs << ref
2139
                    STDOUT.puts("#{index+1}: Template #{t["name"]} in #{datacenter.name} Location: #{location}")
2140
                    index += 1
2141
                end
2142

    
2143
                STDOUT.puts("#{template_refs.size+1}: None of the above.")
2144

    
2145
                loop do
2146
                    STDOUT.print("\nFrom the list above, please \e[95mpick a number\e[39m in order to specify the template: ")
2147
                    template_index = STDIN.gets.strip.to_i
2148
                    next if template_index == 0 || template_index - 1 < 0 || template_index > template_refs.size + 1
2149
                    template_ref  = template_refs[template_index-1] rescue nil
2150
                    break
2151
                end
2152

    
2153
                STDOUT.puts
2154
                STDOUT.puts "-" * 80
2155
            end
2156

    
2157
            # Get OpenNebulas's template
2158
            one_template = OpenNebula::Template.new_with_id(template["ID"], one_client)
2159
            STDOUT.puts
2160

    
2161
            if !template_ref
2162
                STDOUT.print "Could not upgrade this template. Not found in vCenter. Do you want to remove it? (y/n) "
2163
                loop do
2164
                    option = STDIN.gets.strip
2165
                    case option
2166
                    when "y"
2167
                        # delete
2168
                        rc = one_template.delete
2169
                        raise "Template #{template["ID"]}: '#{template["NAME"]}' could not be deleted. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2170

    
2171
                        STDOUT.puts("\nTemplate #{template["ID"]}: '#{template["NAME"]}' has been \e[93mdeleted\e[39m.")
2172
                        break
2173
                    when "n"
2174
                        STDOUT.puts("\nTemplate #{template["ID"]}: '#{template["NAME"]}' is \e[93mbroken\e[39m. Please inspect it manually after the upgrade.")
2175
                        STDOUT.puts("\nPress any key to continue.\n")
2176
                        STDIN.gets
2177
                        break
2178
                    end
2179
                end
2180
                next
2181
            end
2182

    
2183
            rc  = one_template.info
2184
            raise "Could not get info for template #{template["ID"]}. Reason: #{rc.message}" if OpenNebula.is_error?(rc)
2185

    
2186
            # Find vcenter template in vc_templates
2187
            vc_template  = nil
2188
            vc_template_object = nil
2189
            vc_templates[vcenter_uuid].each do |ref, value|
2190
                if ref == template_ref
2191
                    vc_template = value
2192
                    vc_template_object = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, template_ref)
2193
                    break
2194
                end
2195
            end
2196

    
2197
            if vc_template.nil?
2198
                raise "Template #{template_name} could not be updated, cannot find vcenter info for this template"
2199
            end
2200

    
2201
            # Migrate USER_INPUTS/RESOURCE_POOL to USER_INPUTS/VCENTER_RESOURCE_POOL
2202
            user_inputs = nil
2203
            if template_user_rp
2204
                inputs = template.retrieve_xmlelements("TEMPLATE/USER_INPUTS").first.to_hash["USER_INPUTS"] rescue nil
2205
                if inputs
2206
                    user_inputs = ""
2207
                    user_inputs << "USER_INPUTS=["
2208
                    inputs.each do |key, value|
2209
                        user_inputs << "#{key}=\"#{value}\",\n"
2210
                    end
2211
                    user_inputs << "VCENTER_RESOURCE_POOL=\"#{template_user_rp}\"\n"
2212
                    user_inputs << "]"
2213
                end
2214
            end
2215

    
2216
            # Prepare VM template with new attributes
2217
            template = ""
2218
            template << "VCENTER_TEMPLATE_REF=\"#{template_ref}\"\n"
2219
            template << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n"
2220
            template << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"
2221
            template << "VCENTER_RESOURCE_POOL=\"#{template_rp}\"\n" if template_rp
2222
            template << user_inputs if template_user_rp
2223

    
2224
            # Try to update VM template
2225
            rc = one_template.update(template, true)
2226
            raise "Template #{template_name} could not be updated. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2227

    
2228
            # Inform what attributes have been added
2229
            STDOUT.puts "\nTemplate \e[96m#{template_name}:\e[39m"
2230
            STDOUT.puts "--- New attribute VCENTER_TEMPLATE_REF=#{template_ref} added\n"
2231
            STDOUT.puts "--- New attribute VCENTER_INSTANCE_ID=#{vcenter_uuid} added\n"
2232
            STDOUT.puts "--- New attribute VCENTER_CCR_REF=#{ccr_ref} added\n"
2233
            STDOUT.puts "--- New attribute VCENTER_RESOURCE_POOL=#{template_rp} added\n" if template_rp
2234
            STDOUT.puts "--- New attribute USER_INPUTS/VCENTER_RESOURCE_POOL=#{template_user_rp} added\n" if template_user_rp
2235

    
2236
            # Prepare template for migration
2237
            xml_doc           = Nokogiri::XML(one_template.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
2238
            xml_template      = xml_doc.root.at_xpath("TEMPLATE")
2239
            # Retrieve and remove existing disks
2240
            existing_disks    = xml_doc.root.xpath("TEMPLATE/DISK").remove
2241
            # Retrieve and remove existing nics
2242
            existing_nics     = xml_doc.root.xpath("TEMPLATE/NIC").remove
2243
            template_id       = one_template["ID"]
2244

    
2245
            # Discover existing disks and/or nics. Note that datastores will
2246
            # be created if the images require them.
2247
            dc = get_dc(vc_template_object)
2248
            dc_name = dc.name
2249
            dc_ref  = dc._ref
2250
            vcenter_name = vi_client.host
2251
            STDOUT.puts "--- Discovering disks and network interfaces inside the template (please be patient)"
2252
            unmanaged = template_unmanaged_discover(vc_template["config.hardware.device"],
2253
                                                    template_cluster,
2254
                                                    ccr_ref,
2255
                                                    vcenter_name,
2256
                                                    vcenter_uuid,
2257
                                                    vcenter_user,
2258
                                                    vcenter_pass,
2259
                                                    vcenter_host,
2260
                                                    dc_name,
2261
                                                    dc_ref,
2262
                                                    ipool,
2263
                                                    vnpool,
2264
                                                    dspool,
2265
                                                    hpool,
2266
                                                    one_client,
2267
                                                    template_ref,
2268
                                                    vc_template["name"],
2269
                                                    template_id,
2270
                                                    one_clusters,
2271
                                                    vcenter_ids)
2272

    
2273
            if !unmanaged[:images].empty?
2274
                STDOUT.puts "--- Adding DISK elements for discovered disks to new XML"
2275
                # Create images for unmanaged disks
2276
                unmanaged[:images].each do |image_id|
2277
                    # Add existing disk to xml
2278
                    disk = xml_template.add_child(xml_doc.create_element("DISK"))
2279
                    disk.add_child(xml_doc.create_element("IMAGE_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{image_id}"))
2280
                    disk.add_child(xml_doc.create_element("OPENNEBULA_MANAGED")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"NO"))
2281
                end
2282
            end
2283

    
2284
            # Add managed disks after unmanaged disks
2285
            xml_template.add_child(existing_disks)
2286

    
2287
            if !unmanaged[:networks].empty?
2288
                STDOUT.puts "--- Adding NIC elements for discovered nics to new XML"
2289
                # Create networks for unmanaged nics
2290
                unmanaged[:networks].each do |network_id|
2291
                    # Add existing nics to xml
2292
                    nic = xml_template.add_child(xml_doc.create_element("NIC"))
2293
                    nic.add_child(xml_doc.create_element("NETWORK_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{network_id}"))
2294
                    nic.add_child(xml_doc.create_element("OPENNEBULA_MANAGED")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"NO"))
2295
                end
2296
            else
2297
                STDOUT.puts "--- All discovered networks are ready to use"
2298
            end
2299

    
2300
            # Add managed disks after unmanaged disks
2301
            xml_template.add_child(existing_nics)
2302

    
2303
            # Remove SCHED_REQUIREMENTS from TEMPLATE
2304
            xml_template.xpath("SCHED_REQUIREMENTS").remove
2305

    
2306
            # Remove KEEP_DISKS_ON_DONE from TEMPLATE
2307
            xml_template.xpath("KEEP_DISKS_ON_DONE").remove
2308

    
2309
            # Remove PUBLIC_CLOUD section from TEMPLATE
2310
            xml_template.xpath("PUBLIC_CLOUD").remove
2311

    
2312
            # Remove RESOURCE_POOL section from TEMPLATE and USER_INPUTS
2313
            xml_template.xpath("RESOURCE_POOL").remove
2314
            xml_template.xpath("USER_INPUTS/RESOURCE_POOL").remove
2315

    
2316
            # Remove VCENTER_DATASTORE section from TEMPLATE and USER_INPUTS
2317
            vcenter_datastore = xml_template.xpath("VCENTER_DATASTORE").text
2318
            xml_template.xpath("VCENTER_DATASTORE").remove
2319
            xml_template.xpath("USER_INPUTS/VCENTER_DATASTORE").remove
2320

    
2321
            # Replace CUSTOMIZATION_SPEC with VCENTER_CUSTOMIZATION_SPEC
2322
            customization_spec = xml_template.xpath("CUSTOMIZATION_SPEC").text
2323
            if !customization_spec.empty?
2324
                xml_template.xpath("CUSTOMIZATION_SPEC").remove
2325
                xml_template.add_child(xml_doc.create_element("VCENTER_CUSTOMIZATION_SPEC")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{customization_spec}"))
2326
            end
2327

    
2328
            # Remove SCHED_DS_REQUIREMENTS, OpenNebula will choose datastores
2329
            # using the clusters associated to datastores
2330
            xml_template.xpath("SCHED_DS_REQUIREMENTS").remove
2331

    
2332
            # If vcenter_datastore is a SYSTEM_DS then it's a storage pod
2333
            # Let's create a SCHED_DS_REQUIREMENTS to force using that datastore
2334
            ds_id = nil
2335
            if !vcenter_datastore.empty?
2336
                ds = find_datastore_by_name(dspool, "#{vcenter_datastore}")
2337
                ds_id   = ds["ID"]
2338
                ds_type = ds["TEMPLATE/TYPE"]
2339
                if ds_type == "SYSTEM_DS"
2340
                    sched_ds_req = one_template["TEMPLATE/SCHED_DS_REQUIREMENTS"]
2341

    
2342
                    if sched_ds_req
2343
                        xml_template.xpath("SCHED_DS_REQUIREMENTS").remove
2344
                        requirements = "ID=#{ds_id} & (#{sched_ds_req})"
2345
                        xml_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"#{requirements}\""))
2346
                    else
2347
                        # Add a SCHED_DS_REQUIREMENTS to template
2348
                        xml_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"ID=#{ds_id}\""))
2349
                    end
2350
                end
2351
            end
2352

    
2353
            #Write new XML template to file
2354
            xml_doc = xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<")
2355
            File.open("#{TEMP_DIR}/one_migrate_template_#{template_id}","w"){|f| f.puts(xml_doc)}
2356
            STDOUT.puts "--- New XML file #{TEMP_DIR}/one_migrate_template_#{template_id} for template \e[96m#{template_name}\e[39m \e[92mwas created and attributes were removed\e[39m\n"
2357
            STDOUT.puts
2358
            STDOUT.puts "-" * 80
2359
            STDOUT.puts
2360

    
2361
        rescue Exception => e
2362
            raise e
2363
        ensure
2364
            vi_client.vim.close if vi_client
2365
        end
2366
    end
2367
end
2368

    
2369
################################################################################
2370
def inspect_vms(vc_vmachines, vc_templates, vc_clusters, one_clusters, vmpool, ipool, tpool, vnpool, dspool, hpool, one_client, vcenter_ids)
2371

    
2372
    # Retrieve vCenter deployed or importer VMs
2373
    vms = vmpool.retrieve_xmlelements("VM[USER_TEMPLATE/PUBLIC_CLOUD/TYPE=\"vcenter\"]")
2374

    
2375
    vms.each do |vm|
2376
        next if !vm["DEPLOY_ID"] # Ignore undeployed vms
2377

    
2378
        begin
2379
            # Refresh pools
2380
            rc = vnpool.info_all
2381
            raise "\n    ERROR! Could not update vnpool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2382

    
2383
            rc = ipool.info_all
2384
            raise "\n    ERROR! Could not update ipool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2385

    
2386
            rc = dspool.info
2387
            raise "\n    ERROR! Could not update dspool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2388

    
2389
            # Find vcenter VM in vc_vmachines
2390
            vm_name = vm["NAME"]
2391
            vm_id   = vm["ID"]
2392

    
2393
            # Get cluster's MOREF and name
2394
            host_id      = vm["HISTORY_RECORDS/HISTORY[last()]/HID"]
2395
            host         = OpenNebula::Host.new_with_id(host_id, one_client)
2396
            rc           = host.info
2397
            raise "\n    ERROR! Could not get host info for wild vm disk. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2398
            ccr_name     = host["NAME"]
2399
            ccr_ref      = host["TEMPLATE/VCENTER_CCR_REF"]
2400
            vcenter_user = host["TEMPLATE/VCENTER_USER"]
2401
            vcenter_pass = host["TEMPLATE/VCENTER_PASSWORD"]
2402
            vcenter_host = host["TEMPLATE/VCENTER_HOST"]
2403
            if !ccr_ref
2404
                raise "VM #{vm_name} could not be updated, cannot find cluster's MOREF"
2405
            end
2406

    
2407
            # Create vi_client
2408
            vi_client    = VCenterDriver::VIClient.new(host_id)
2409
            vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
2410
            vcenter_name = vi_client.host
2411

    
2412
            # Is VM a wild?
2413
            vm_wild = vm["TEMPLATE/IMPORTED"] == "YES"
2414

    
2415
            # Try to find the vCenter object comparing its uuid with the DEPLOY_ID
2416
            vc_vmachine        = nil
2417
            vm_ref             = nil
2418
            vc_vmachine_object = nil
2419

    
2420
            machines_found = vc_vmachines[vcenter_uuid].select do |ref, value|
2421
                value["config.uuid"] == vm["DEPLOY_ID"]
2422
            end
2423

    
2424
            if machines_found.size == 0
2425
                STDOUT.puts "VM \e[96m#{vm_name}\e[39m could not be migrated, \e[91mcannot find this VM in objects retrieved\e[39m,\n"\
2426
                            "maybe it was deleted in vCenter but not in OpenNebula?"
2427
                STDOUT.puts
2428
                STDOUT.puts "-" * 80
2429
                STDOUT.puts
2430
                next
2431
            end
2432

    
2433
            if machines_found.size > 1
2434
                # We have several vCenter objects with the same UUID the admin
2435
                # must help us to know which VM is the one we're looking for
2436
                vm_refs   = []
2437
                vm_values = []
2438
                index     = 0
2439
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2440
                STDOUT.puts("\nWhich vCenter VM is represented by OpenNebula \e[96mVM #{vm_name}?\e[39m\n")
2441
                STDOUT.puts
2442

    
2443
                vc_vmachines[vcenter_uuid].each do |ref, v|
2444
                    if v["config.uuid"] == vm["DEPLOY_ID"]
2445
                        item = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2446
                        while !item.instance_of? RbVmomi::VIM::Datacenter
2447
                            item = item.parent
2448
                            if item.nil?
2449
                                raise "Could not find the Datacenter associated to this VM"
2450
                            end
2451
                        end
2452
                        datacenter = item
2453

    
2454
                        vm_refs   << ref
2455
                        vm_values << v
2456
                        STDOUT.puts("#{index+1}: VM #{v["name"]} in #{datacenter.name}")
2457
                        index += 1
2458
                    end
2459
                end
2460

    
2461
                loop do
2462
                    STDOUT.print("\nFrom the list above, please \e[95mpick up one number\e[39m in order to specify the right VM: ")
2463
                    vm_index = STDIN.gets.strip.to_i
2464
                    next if vm_index == 0 || vm_index - 1 < 0 || vm_index > vm_refs.size
2465
                    vm_ref  = vm_refs[vm_index-1] rescue nil
2466
                    vc_vmachine = vm_values[vm_index-1] rescue nil
2467
                    vc_vmachine_object = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, vm_ref)
2468
                    break if vm_ref
2469
                end
2470

    
2471
                STDOUT.puts
2472
                STDOUT.puts "-" * 80
2473
                STDOUT.puts
2474

    
2475
            else
2476
                # We have only found one VM where the DEPLOY_ID matches the config.uuid
2477
                vc_vmachines[vcenter_uuid].each do |ref, value|
2478
                    if value["config.uuid"] == vm["DEPLOY_ID"]
2479
                        vc_vmachine = value
2480
                        vc_vmachine_object = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2481
                        vm_ref = ref
2482
                        break
2483
                    end
2484
                end
2485
            end
2486

    
2487
            # We have to discriminate between Wild vms and VMs deployed by OpenNebula
2488
            if vm_wild
2489
                template_ref = vm_ref # The template ref is the VM's moref
2490
            else
2491
                # If the VM was deployed by OpenNebula the ref or uuid are in the USER_TEMPLATE
2492
                template_ref  = vm["USER_TEMPLATE/PUBLIC_CLOUD/VCENTER_REF"]
2493
                template_uuid = vm["USER_TEMPLATE/PUBLIC_CLOUD/VM_TEMPLATE"]
2494

    
2495
                # We try to check if the template's moref found inside the XML template
2496
                # is found in the templates retrieved from vcenter only once
2497
                if template_ref
2498

    
2499
                    templates_found = vc_templates[vcenter_uuid].select do |ref, value|
2500
                        template_ref == ref
2501
                    end
2502

    
2503
                    if templates_found.size != 1
2504
                        template_ref = nil
2505
                    end
2506
                end
2507

    
2508
                # Try to get moref using the templates uuid note that that uuid
2509
                # is not unique
2510
                templates_same_uuid = {}
2511
                if !template_ref && template_uuid
2512
                    templates_found = 0
2513
                    vc_templates[vcenter_uuid].each do |ref, value|
2514
                        if value["config.uuid"] == template_uuid
2515
                            templates_found += 1
2516
                            templates_same_uuid[ref] = value
2517
                            if templates_found > 1
2518
                                template_ref = nil
2519
                            else
2520
                                template_ref = ref
2521
                            end
2522
                        end
2523
                    end
2524
                end
2525

    
2526
                if !template_ref
2527
                    STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2528
                    STDOUT.puts("\nWhich vCenter template is associated with OpenNebula \e[96mVM #{vm_name}?\e[39m\n")
2529
                    STDOUT.puts
2530

    
2531
                    index = 0
2532
                    template_refs  = []
2533

    
2534
                    if templates_same_uuid.length > 1
2535
                        # Choose only between those that have the same UUID
2536
                        templates_list = templates_same_uuid
2537
                    else
2538
                        templates_list = vc_templates[vcenter_uuid]
2539
                    end
2540

    
2541
                    templates_list.each do |ref, t|
2542
                        item = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2543

    
2544
                        folders = []
2545
                        while !item.instance_of? RbVmomi::VIM::Datacenter
2546
                            item = item.parent
2547
                            if !item.instance_of?(RbVmomi::VIM::Datacenter)
2548
                                if item.name != "vm"
2549
                                    folders << item.name
2550
                                else
2551
                                    folders << ""
2552
                                end
2553
                            end
2554
                            if item.nil?
2555
                                raise "Could not find the Datacenter for the template"
2556
                            end
2557
                        end
2558
                        datacenter = item
2559
                        location   = folders.reverse.join("/")
2560
                        location = "/" if location.empty?
2561

    
2562

    
2563
                        template_refs << ref
2564
                        STDOUT.puts("#{index+1}: Template #{t["name"]} in Datacenter #{datacenter.name} Location: #{location}")
2565
                        index += 1
2566
                    end
2567

    
2568
                    STDOUT.puts("#{template_refs.size+1}: None of the above.")
2569

    
2570
                    loop do
2571
                        STDOUT.print("\nFrom the list above, please \e[95mpick up one number\e[39m in order to specify the venter template that this VM was based on: ")
2572
                        template_index = STDIN.gets.strip.to_i
2573
                        next if template_index == 0 || template_index - 1 < 0 || template_index > template_refs.size + 1
2574
                        template_ref  = template_refs[template_index-1] rescue nil
2575
                        break
2576
                    end
2577
                end
2578

    
2579
                STDOUT.puts
2580
                STDOUT.puts "-" * 80
2581
                STDOUT.puts
2582
            end
2583

    
2584
            # Get VM's datacenter name
2585
            dc = get_dc(vc_vmachine_object)
2586
            dc_name = dc.name
2587
            dc_ref  = dc._ref
2588

    
2589
            # Get xml template from tmp with unmanaged disks and nics and new attributes
2590
            template_id  = vm["TEMPLATE/TEMPLATE_ID"]
2591
            template_xml = nil
2592

    
2593
            if !vm_wild
2594
                template_filename = "#{TEMP_DIR}/one_migrate_template_#{template_id}"
2595
                if File.exist?("#{template_filename}")
2596
                    template_xml = File.open(template_filename) { |f| Nokogiri::XML(f, nil, "UTF-8"){|c| c.default_xml.noblanks} }
2597
                end
2598
            end
2599

    
2600
            # Create a Nokogiri XML representing the VM's template
2601
            xml_doc = Nokogiri::XML(vm.to_xml, nil, "UTF-8"){|c| c.default_xml.noblanks}
2602

    
2603
            # Replace VM's deploy_id uuid with moref
2604
            xml_deploy_id  = xml_doc.root.at_xpath("DEPLOY_ID")
2605
            xml_deploy_id.content = vc_vmachine_object._ref
2606

    
2607
            # Inform about the changes
2608
            STDOUT.puts "VM \e[96m#{vm_name}\e[39m:"
2609
            STDOUT.puts
2610
            STDOUT.puts "--- DEPLOY_ID has been changed to #{vc_vmachine_object._ref}"
2611

    
2612
            # Retrieve and remove disks and nics from vm
2613
            existing_disks = xml_doc.root.xpath("TEMPLATE/DISK").remove # Retrieve and remove existing disks
2614
            existing_nics  = xml_doc.root.xpath("TEMPLATE/NIC").remove  # Retrieve and remove existing nics
2615

    
2616
            # Discover existing disks and/or nics
2617
            # It will return an extraconfig for VM reconfigure
2618
            extraconfig = vm_unmanaged_discover(vc_vmachine["config.hardware.device"],
2619
                                                xml_doc,
2620
                                                template_xml,
2621
                                                existing_disks,
2622
                                                existing_nics,
2623
                                                ccr_name,
2624
                                                ccr_ref,
2625
                                                vcenter_name,
2626
                                                vcenter_uuid,
2627
                                                vcenter_user,
2628
                                                vcenter_pass,
2629
                                                vcenter_host,
2630
                                                dc_name,
2631
                                                dc_ref,
2632
                                                ipool,
2633
                                                vnpool,
2634
                                                dspool,
2635
                                                hpool,
2636
                                                one_client,
2637
                                                vi_client,
2638
                                                vm_wild,
2639
                                                vm_id,
2640
                                                vc_vmachine["name"],
2641
                                                vc_templates[vcenter_uuid],
2642
                                                vm_ref,
2643
                                                vc_vmachines[vcenter_uuid],
2644
                                                template_ref,
2645
                                                one_clusters,
2646
                                                vcenter_ids)
2647

    
2648
            # If VM has TOKEN=YES for CONTEXT we must generate a token.txt file from
2649
            # the variable openebula.token or try to extract it from context
2650

    
2651
            if vm["TEMPLATE/CONTEXT/TOKEN"] == "YES"
2652
                STDOUT.puts
2653
                STDOUT.puts "VM #{vm_name} generating token.txt..."
2654
                onegate_token = vc_vmachine["config.extraConfig"].select{|val| val[:key]=="opennebula.token"}.first.value rescue nil
2655

    
2656
                # For older versions try to extract if from context inside VM
2657
                if !onegate_token
2658
                    context = vc_vmachine["config.extraConfig"].select{|val| val[:key]=="guestinfo.opennebula.context"}.first.value rescue nil
2659
                    if context
2660
                        onegate_token = Base64.decode64(context).split("\n").select{|line| line.start_with?("ONEGATE_TOKEN")}.first[/ONEGATE_TOKEN='(.*?)'/,1] rescue nil
2661
                    end
2662
                end
2663
                STDOUT.put "--- Could not extract token from vcenter vm or context section" if !onegate_token
2664
                File.open("/var/lib/one/vms/#{vm_id}/token.txt",'w'){|f| f.puts(onegate_token)}
2665
            end
2666

    
2667
            # Add opennebula.disk elements to vcenter VM so unmanaged disks are referenced
2668
            spec = {}
2669
            spec[:extraConfig]  = extraconfig if !extraconfig.empty?
2670
            vc_vmachine_object.ReconfigVM_Task(:spec => spec).wait_for_completion
2671

    
2672
            STDOUT.puts
2673
            STDOUT.puts "-" * 80
2674
            STDOUT.puts
2675
        rescue Exception => e
2676
            raise e
2677
        ensure
2678
            vi_client.vim.close if vi_client
2679
        end
2680
    end
2681
end
2682

    
2683
################################################################################
2684
# Pre-migrator tool                                                            #
2685
################################################################################
2686

    
2687
CommandParser::CmdParser.new(ARGV) do
2688
    usage "`vcenter_one54_pre` [<options>]"
2689
    description ""
2690
    version OpenNebulaHelper::ONE_VERSION
2691

    
2692
    helper=OpenNebulaHelper::OneHelper.new
2693

    
2694
    before_proc do
2695
        helper.set_client(options)
2696
    end
2697

    
2698
    cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE]
2699
    set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS
2700

    
2701
    option CommandParser::OPTIONS
2702

    
2703
    main do
2704
        begin
2705
            msg = "  vCenter pre-migrator tool for OpenNebula 5.4 - Version: 1.0"
2706
            logo_banner(msg)
2707

    
2708
            # Initialize opennebula client
2709
            one_client = OpenNebula::Client.new()
2710
            vcenter_instances = []
2711

    
2712
            hpool = OpenNebula::HostPool.new(one_client)
2713
            rc = hpool.info
2714

    
2715
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2716

    
2717
            cpool = OpenNebula::ClusterPool.new(one_client)
2718
            rc = cpool.info
2719
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2720

    
2721
            vc_clusters   = {}
2722
            vc_datastores = {}
2723
            vc_networks   = {}
2724
            vc_vmachines  = {}
2725
            vc_templates  = {}
2726

    
2727
            banner " PHASE 0 - Before running the script please read the following notes", true
2728

    
2729
            STDOUT.puts
2730
            STDOUT.puts("- Please check that you have set PERSISTENT_ONLY=\"NO\" and REQUIRED_ATTRS=\"\"\n"\
2731
                        "  in you DS_MAD_CONF vcenter inside the /etc/one/oned.conf and that you have\n"\
2732
                        "  restarted your OpenNebula services to apply the new configuration before\n"\
2733
                        "  launching the script.")
2734
            STDOUT.puts
2735
            STDOUT.puts("- Edit the file \e[92m/var/lib/one/remotes/datastore/vcenter/rm\e[39m and replace the\n"\
2736
                        "  following lines:\n\n"\
2737
                        "  \e[96mvi_client.delete_virtual_disk(img_src,\n"\
2738
                        "                                ds_name)\e[39m \n\n"\
2739
                        "  with the following lines:\n\n"\
2740
                        "  \e[96mif drv_action[\"/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_IMPORTED\"] != \"YES\"\n"\
2741
                        "       vi_client.delete_virtual_disk(img_src,ds_name) \n"\
2742
                        "  end\e[39m \n\n"\
2743
                        "  in order to avoid that you accidentally remove a virtual hard disk from a template \n"\
2744
                        "  or wild VM when you delete an image.")
2745
            STDOUT.puts
2746
            STDOUT.puts("- Note that this script may take some time to perform complex tasks so \e[96mplease be patient.\e[39m")
2747
            STDOUT.puts
2748
            STDOUT.puts("- Although this scripts will do its best to be fully automated there may be situations\n"\
2749
                        "  where a manual intervention is needed, in that case a \e[93mWARNING\e[39m will be shown.")
2750
            STDOUT.puts
2751
            STDOUT.puts("- The virtual networks that represent port groups found inside existing templates\n"\
2752
                        "  will have an Ethernet address range with 255 MACs in the pool. You may want to\n"\
2753
                        "  change or increase this address range after the pre-migrator tool finishes.")
2754
            STDOUT.puts
2755
            STDOUT.puts("- It's advisable to disable the Sunstone user interface before launching this script\n"\
2756
                        "  in order to avoid that OpenNebula objects created by users while\n"\
2757
                        "  the script is running are not pre-migrated by the tool.")
2758
            STDOUT.puts
2759
            STDOUT.puts("- This script can be executed as many times as you wish. It will update previous\n"\
2760
                        "  results and XML template will be always overwritten.")
2761
            STDOUT.puts
2762
            STDOUT.puts("\e[93mDon't forget to restart OpenNebula if you have made changes!\e[39m")
2763

    
2764
            STDOUT.print("\nDo you want to continue? ([y]/n): ")
2765

    
2766
            exit! if STDIN.gets.strip.downcase == 'n'
2767

    
2768
            banner " PHASE 1 - Retrieve objects from vCenter instances", true
2769

    
2770
            STDOUT.puts
2771
            STDOUT.puts "Inventory objects are being retrieved, \e[96mplease be patient...\e[39m"
2772
            STDOUT.puts
2773

    
2774
            # For each vCenter host we:
2775
            # - Create a rbvmomi connection
2776
            # - Generate views for clusters, datastores, networks and VMs
2777

    
2778
            hpool.each do |host|
2779
                next if host['VM_MAD'] != "vcenter"
2780

    
2781
                vi_client = VCenterDriver::VIClient.new(host["ID"])
2782
                vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
2783
                if vcenter_instances.include?(vcenter_uuid)
2784
                    vi_client.vim.close
2785
                    next
2786
                end
2787
                vcenter_instances << vcenter_uuid
2788

    
2789
                # Retrieve vCenter Managed Objects
2790
                vc_clusters[vcenter_uuid]   = retrieve_vcenter_clusters(vi_client)
2791
                vc_datastores[vcenter_uuid] = retrieve_vcenter_datastores(vi_client)
2792
                vc_networks[vcenter_uuid]   = retrieve_vcenter_networks(vi_client)
2793
                vc_vmachines[vcenter_uuid], vc_templates[vcenter_uuid] = retrieve_vcenter_vms(vi_client)
2794

    
2795
                STDOUT.puts "--- #{host["TEMPLATE/VCENTER_HOST"]} \e[92mobjects have been retrieved\e[39m"
2796
            end
2797

    
2798
            STDOUT.puts
2799
            STDOUT.puts "All vCenter objects have been retrieved, thanks for your patience."
2800

    
2801
            # Control what objects id have been modified
2802
            vcenter_ids = {}
2803
            vcenter_ids[:host]  = []
2804
            vcenter_ids[:ds]    = []
2805
            vcenter_ids[:vnet]  = []
2806
            vcenter_ids[:image] = []
2807

    
2808
            banner " PHASE 2 - Add new attributes to existing hosts", true
2809
            add_new_host_attrs(vc_clusters, hpool, one_client, vcenter_ids)
2810

    
2811
            banner " PHASE 3 - Create OpenNebula clusters if needed", true
2812
            STDOUT.puts
2813

    
2814
            one_clusters = create_new_clusters(vc_clusters, hpool, cpool, one_client)
2815

    
2816
            dspool = OpenNebula::DatastorePool.new(one_client)
2817
            rc = dspool.info
2818
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2819

    
2820
            rc = hpool.info # Update host pool to get new attributes
2821
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2822

    
2823
            rc = cpool.info # Update cluster pool to get new clusters
2824
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2825

    
2826
            extended_message = " - Add new attributes to datastores\n"\
2827
                               " - Create SYSTEM datastores if needed\n"\
2828
                               " - Assign datastores to OpenNebula Clusters"
2829

    
2830
            banner " PHASE 4 - Inspect existing datatores ", true, extended_message
2831

    
2832
            inspect_datastores(vc_datastores, vc_clusters, one_clusters, dspool, hpool, one_client, vcenter_ids)
2833

    
2834
            rc = dspool.info # Refresh datastore pool
2835
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2836

    
2837
            vnpool = OpenNebula::VirtualNetworkPool.new(one_client)
2838
            rc = vnpool.info_all
2839
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2840

    
2841
            extended_message = " - Add new attributes to vnets\n"\
2842
                               " - Assign vnets to OpenNebula Clusters"
2843
            banner " PHASE 5 - Add new attributes to existing vnets", true, extended_message
2844
            inspect_networks(vc_networks, vc_clusters, one_clusters, vnpool, hpool, one_client, vcenter_ids)
2845

    
2846
            ipool = OpenNebula::ImagePool.new(one_client)
2847
            rc = ipool.info_all
2848
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2849

    
2850
            banner " PHASE 6 - Add new attributes to existing images", true
2851
            add_new_image_attrs(ipool, one_client, vcenter_ids)
2852

    
2853
            rc = ipool.info_all
2854
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2855

    
2856
            tpool = OpenNebula::TemplatePool.new(one_client)
2857
            rc = tpool.info_all
2858
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2859

    
2860
            extended_message = " - Add new attributes to existing templates\n"\
2861
                               " - Discover nics and disks inside templates\n"\
2862
                               " - Import datastores where discovered virtual disks are found if needed.\n"\
2863
                               " - Create images for discovered virtual hard disks\n"\
2864
                               " - Create vnets for discovered port groups\n"\
2865
                               " - Prepare XML VM templates removing old or deprecated attributes\n"
2866

    
2867
            banner " PHASE 7 - Inspect existing VM templates", true, extended_message
2868

    
2869
            inspect_templates(vc_templates, vc_clusters, one_clusters, tpool, ipool, vnpool, dspool, hpool, one_client, vcenter_ids)
2870

    
2871
            vmpool = OpenNebula::VirtualMachinePool.new(one_client)
2872
            rc = vmpool.info_all
2873
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2874

    
2875
            extended_message = " - Add new attributes to existing VMs\n"\
2876
                               " - Discover nics and disks inside VMs\n"\
2877
                               " - Import datastores where discovered virtual disks are found if needed.\n"\
2878
                               " - Create images for discovered virtual hard disks\n"\
2879
                               " - Create vnets for discovered port groups\n"\
2880
                               " - Prepare XML VM templates removing old or deprecated attributes\n"\
2881
                               " - Reconfigure vCenter VM to add unmanaged disks and nics references\n"\
2882
                               " - DEPLOY_ID will get VM's managed object reference\n"
2883

    
2884
            banner " PHASE 8 - Inspect existing VMs", true
2885
            STDOUT.puts
2886
            inspect_vms(vc_vmachines, vc_templates, vc_clusters, one_clusters, vmpool, ipool, tpool, vnpool, dspool, hpool, one_client, vcenter_ids)
2887

    
2888
            if !vcenter_ids[:host].empty?
2889
                banner " PHASE  9 - Prepare XML templates for hosts without deprecated attributes", true
2890
                prepare_host_xml_templates(vcenter_ids[:host], one_clusters, one_client)
2891
            end
2892

    
2893
            if !vcenter_ids[:ds].empty?
2894
                banner " PHASE 10 - Prepare XML templates for datastores without deprecated attributes", true
2895
                prepare_ds_xml_templates(vcenter_ids[:ds], one_client)
2896
            end
2897

    
2898
            if !vcenter_ids[:vnet].empty?
2899
                banner " PHASE 11 - Prepare XML templates for vnets without deprecated attributes", true
2900
                prepare_vnet_xml_templates(vcenter_ids[:vnet], one_client)
2901
            end
2902

    
2903
            if !vcenter_ids[:image].empty?
2904
                banner " PHASE 12 - Prepare XML templates for images without deprecated attributes", true
2905
                prepare_image_xml_templates(vcenter_ids[:image], hpool, one_client)
2906
            end
2907

    
2908
            puts ""
2909

    
2910
            exit_code 0
2911
        rescue Exception => e
2912
            STDERR.puts "An error occurred when pre-migrating OpenNebula:\n"\
2913
                        "#{e.message}\"\n#{e.backtrace}"
2914
            exit -1
2915
        end
2916
    end
2917
end