Statistics
| Branch: | Tag: | Revision:

one / src / onedb / vcenter_one54_pre.rb @ 33b9d899

History | View | Annotate | Download (131 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

    
2160
            STDOUT.puts
2161

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

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

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

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

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

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

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

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

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

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

    
2246
            # Discover existing disks and/or nics. Note that datastores will
2247
            # be created if the images require them.
2248
            dc = get_dc(vc_template_object)
2249
            dc_name = dc.name
2250
            dc_ref  = dc._ref
2251
            vcenter_name = vi_client.host
2252
            STDOUT.puts "--- Discovering disks and network interfaces inside the template (please be patient)"
2253

    
2254
            devices = vc_template["config.hardware.device"]
2255

    
2256
            has_spaces = false
2257
            devices.each do |device|
2258
                if !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil?
2259
                    image_path = device.backing.fileName.sub(/^\[(.*?)\] /, "")
2260
                    if image_path.include?(" ")
2261
                        has_spaces = true
2262
                        break
2263
                    end
2264
                end
2265
            end
2266

    
2267
            if has_spaces
2268
                STDOUT.puts
2269
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2270
                STDOUT.puts "Template #{one_template["ID"]}: '#{one_template["NAME"]}' is not compatible."
2271
                STDOUT.puts
2272
                STDOUT.puts "Images in this template contain spaces, which is not supported."
2273
                STDOUT.puts "You need to remove the spaces from the paths and import it again"
2274
                STDOUT.puts "in OpenNebula 5.4."
2275
                STDOUT.puts
2276
                STDOUT.puts "Press 'y' to delete the template from OpenNebula."
2277
                STDOUT.puts "Alternatively press 'q' to quit the premigrator"
2278
                STDOUT.puts "in order to fix the path before running the premigrator again."
2279
                STDOUT.puts "(y/q)"
2280
                STDOUT.puts
2281

    
2282
                loop do
2283
                    option = STDIN.gets.strip
2284
                    case option
2285
                    when "y"
2286
                        rc = one_template.delete
2287
                        raise "Template #{one_template["ID"]}: '#{one_template["NAME"]}' could not be deleted. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2288
                        break
2289
                    when "q"
2290
                        exit 0
2291
                    end
2292
                end
2293
                next
2294
            end
2295

    
2296
            unmanaged = template_unmanaged_discover(devices,
2297
                                                    template_cluster,
2298
                                                    ccr_ref,
2299
                                                    vcenter_name,
2300
                                                    vcenter_uuid,
2301
                                                    vcenter_user,
2302
                                                    vcenter_pass,
2303
                                                    vcenter_host,
2304
                                                    dc_name,
2305
                                                    dc_ref,
2306
                                                    ipool,
2307
                                                    vnpool,
2308
                                                    dspool,
2309
                                                    hpool,
2310
                                                    one_client,
2311
                                                    template_ref,
2312
                                                    vc_template["name"],
2313
                                                    template_id,
2314
                                                    one_clusters,
2315
                                                    vcenter_ids)
2316

    
2317
            if !unmanaged[:images].empty?
2318
                STDOUT.puts "--- Adding DISK elements for discovered disks to new XML"
2319
                # Create images for unmanaged disks
2320
                unmanaged[:images].each do |image_id|
2321
                    # Add existing disk to xml
2322
                    disk = xml_template.add_child(xml_doc.create_element("DISK"))
2323
                    disk.add_child(xml_doc.create_element("IMAGE_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{image_id}"))
2324
                    disk.add_child(xml_doc.create_element("OPENNEBULA_MANAGED")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"NO"))
2325
                end
2326
            end
2327

    
2328
            # Add managed disks after unmanaged disks
2329
            xml_template.add_child(existing_disks)
2330

    
2331
            if !unmanaged[:networks].empty?
2332
                STDOUT.puts "--- Adding NIC elements for discovered nics to new XML"
2333
                # Create networks for unmanaged nics
2334
                unmanaged[:networks].each do |network_id|
2335
                    # Add existing nics to xml
2336
                    nic = xml_template.add_child(xml_doc.create_element("NIC"))
2337
                    nic.add_child(xml_doc.create_element("NETWORK_ID")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{network_id}"))
2338
                    nic.add_child(xml_doc.create_element("OPENNEBULA_MANAGED")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"NO"))
2339
                end
2340
            else
2341
                STDOUT.puts "--- All discovered networks are ready to use"
2342
            end
2343

    
2344
            # Add managed disks after unmanaged disks
2345
            xml_template.add_child(existing_nics)
2346

    
2347
            # Remove SCHED_REQUIREMENTS from TEMPLATE
2348
            xml_template.xpath("SCHED_REQUIREMENTS").remove
2349

    
2350
            # Remove KEEP_DISKS_ON_DONE from TEMPLATE
2351
            xml_template.xpath("KEEP_DISKS_ON_DONE").remove
2352

    
2353
            # Remove PUBLIC_CLOUD section from TEMPLATE
2354
            xml_template.xpath("PUBLIC_CLOUD").remove
2355

    
2356
            # Remove RESOURCE_POOL section from TEMPLATE and USER_INPUTS
2357
            xml_template.xpath("RESOURCE_POOL").remove
2358
            xml_template.xpath("USER_INPUTS/RESOURCE_POOL").remove
2359

    
2360
            # Remove VCENTER_DATASTORE section from TEMPLATE and USER_INPUTS
2361
            vcenter_datastore = xml_template.xpath("VCENTER_DATASTORE").text
2362
            xml_template.xpath("VCENTER_DATASTORE").remove
2363
            xml_template.xpath("USER_INPUTS/VCENTER_DATASTORE").remove
2364

    
2365
            # Replace CUSTOMIZATION_SPEC with VCENTER_CUSTOMIZATION_SPEC
2366
            customization_spec = xml_template.xpath("CUSTOMIZATION_SPEC").text
2367
            if !customization_spec.empty?
2368
                xml_template.xpath("CUSTOMIZATION_SPEC").remove
2369
                xml_template.add_child(xml_doc.create_element("VCENTER_CUSTOMIZATION_SPEC")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"#{customization_spec}"))
2370
            end
2371

    
2372
            # Remove SCHED_DS_REQUIREMENTS, OpenNebula will choose datastores
2373
            # using the clusters associated to datastores
2374
            xml_template.xpath("SCHED_DS_REQUIREMENTS").remove
2375

    
2376
            # If vcenter_datastore is a SYSTEM_DS then it's a storage pod
2377
            # Let's create a SCHED_DS_REQUIREMENTS to force using that datastore
2378
            ds_id = nil
2379
            if !vcenter_datastore.empty?
2380
                ds = find_datastore_by_name(dspool, "#{vcenter_datastore}")
2381
                ds_id   = ds["ID"]
2382
                ds_type = ds["TEMPLATE/TYPE"]
2383
                if ds_type == "SYSTEM_DS"
2384
                    sched_ds_req = one_template["TEMPLATE/SCHED_DS_REQUIREMENTS"]
2385

    
2386
                    if sched_ds_req
2387
                        xml_template.xpath("SCHED_DS_REQUIREMENTS").remove
2388
                        requirements = "ID=#{ds_id} & (#{sched_ds_req})"
2389
                        xml_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"#{requirements}\""))
2390
                    else
2391
                        # Add a SCHED_DS_REQUIREMENTS to template
2392
                        xml_template.add_child(xml_doc.create_element("SCHED_DS_REQUIREMENTS")).add_child(Nokogiri::XML::CDATA.new(xml_doc,"\"ID=#{ds_id}\""))
2393
                    end
2394
                end
2395
            end
2396

    
2397
            #Write new XML template to file
2398
            xml_doc = xml_doc.root.to_s.gsub(/>\s*/, ">").gsub(/\s*</, "<")
2399
            File.open("#{TEMP_DIR}/one_migrate_template_#{template_id}","w"){|f| f.puts(xml_doc)}
2400
            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"
2401
            STDOUT.puts
2402
            STDOUT.puts "-" * 80
2403
            STDOUT.puts
2404

    
2405
        rescue Exception => e
2406
            raise e
2407
        ensure
2408
            vi_client.vim.close if vi_client
2409
        end
2410
    end
2411
end
2412

    
2413
################################################################################
2414
def inspect_vms(vc_vmachines, vc_templates, vc_clusters, one_clusters, vmpool, ipool, tpool, vnpool, dspool, hpool, one_client, vcenter_ids)
2415

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

    
2419
    vms.each do |vm|
2420
        next if !vm["DEPLOY_ID"] # Ignore undeployed vms
2421

    
2422
        begin
2423
            # Refresh pools
2424
            rc = vnpool.info_all
2425
            raise "\n    ERROR! Could not update vnpool. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2426

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

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

    
2433
            # Find vcenter VM in vc_vmachines
2434
            vm_name = vm["NAME"]
2435
            vm_id   = vm["ID"]
2436

    
2437
            # Get cluster's MOREF and name
2438
            host_id      = vm["HISTORY_RECORDS/HISTORY[last()]/HID"]
2439
            host         = OpenNebula::Host.new_with_id(host_id, one_client)
2440
            rc           = host.info
2441
            raise "\n    ERROR! Could not get host info for wild vm disk. Reason #{rc.message}" if OpenNebula.is_error?(rc)
2442
            ccr_name     = host["NAME"]
2443
            ccr_ref      = host["TEMPLATE/VCENTER_CCR_REF"]
2444
            vcenter_user = host["TEMPLATE/VCENTER_USER"]
2445
            vcenter_pass = host["TEMPLATE/VCENTER_PASSWORD"]
2446
            vcenter_host = host["TEMPLATE/VCENTER_HOST"]
2447
            if !ccr_ref
2448
                raise "VM #{vm_name} could not be updated, cannot find cluster's MOREF"
2449
            end
2450

    
2451
            # Create vi_client
2452
            vi_client    = VCenterDriver::VIClient.new(host_id)
2453
            vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
2454
            vcenter_name = vi_client.host
2455

    
2456
            # Is VM a wild?
2457
            vm_wild = vm["TEMPLATE/IMPORTED"] == "YES"
2458

    
2459
            # Try to find the vCenter object comparing its uuid with the DEPLOY_ID
2460
            vc_vmachine        = nil
2461
            vm_ref             = nil
2462
            vc_vmachine_object = nil
2463

    
2464
            machines_found = vc_vmachines[vcenter_uuid].select do |ref, value|
2465
                value["config.uuid"] == vm["DEPLOY_ID"]
2466
            end
2467

    
2468
            if machines_found.size == 0
2469
                STDOUT.puts "VM \e[96m#{vm_name}\e[39m could not be migrated, \e[91mcannot find this VM in objects retrieved\e[39m,\n"\
2470
                            "maybe it was deleted in vCenter but not in OpenNebula?"
2471
                STDOUT.puts
2472
                STDOUT.puts "Press any key to continue."
2473
                STDIN.gets
2474
                STDOUT.puts
2475
                STDOUT.puts "-" * 80
2476
                STDOUT.puts
2477
                next
2478
            end
2479

    
2480
            if machines_found.size > 1
2481
                # We have several vCenter objects with the same UUID the admin
2482
                # must help us to know which VM is the one we're looking for
2483
                vm_refs   = []
2484
                vm_values = []
2485
                index     = 0
2486
                STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2487
                STDOUT.puts("\nWhich vCenter VM is represented by OpenNebula \e[96mVM #{vm_name}?\e[39m\n")
2488
                STDOUT.puts
2489

    
2490
                vc_vmachines[vcenter_uuid].each do |ref, v|
2491
                    if v["config.uuid"] == vm["DEPLOY_ID"]
2492
                        item = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2493
                        while !item.instance_of? RbVmomi::VIM::Datacenter
2494
                            item = item.parent
2495
                            if item.nil?
2496
                                raise "Could not find the Datacenter associated to this VM"
2497
                            end
2498
                        end
2499
                        datacenter = item
2500

    
2501
                        vm_refs   << ref
2502
                        vm_values << v
2503
                        STDOUT.puts("#{index+1}: VM #{v["name"]} in #{datacenter.name}")
2504
                        index += 1
2505
                    end
2506
                end
2507

    
2508
                loop do
2509
                    STDOUT.print("\nFrom the list above, please \e[95mpick up one number\e[39m in order to specify the right VM: ")
2510
                    vm_index = STDIN.gets.strip.to_i
2511
                    next if vm_index == 0 || vm_index - 1 < 0 || vm_index > vm_refs.size
2512
                    vm_ref  = vm_refs[vm_index-1] rescue nil
2513
                    vc_vmachine = vm_values[vm_index-1] rescue nil
2514
                    vc_vmachine_object = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, vm_ref)
2515
                    break if vm_ref
2516
                end
2517

    
2518
                STDOUT.puts
2519
                STDOUT.puts "-" * 80
2520
                STDOUT.puts
2521

    
2522
            else
2523
                # We have only found one VM where the DEPLOY_ID matches the config.uuid
2524
                vc_vmachines[vcenter_uuid].each do |ref, value|
2525
                    if value["config.uuid"] == vm["DEPLOY_ID"]
2526
                        vc_vmachine = value
2527
                        vc_vmachine_object = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2528
                        vm_ref = ref
2529
                        break
2530
                    end
2531
                end
2532
            end
2533

    
2534
            # We have to discriminate between Wild vms and VMs deployed by OpenNebula
2535
            if vm_wild
2536
                template_ref = vm_ref # The template ref is the VM's moref
2537
            else
2538
                # If the VM was deployed by OpenNebula the ref or uuid are in the USER_TEMPLATE
2539
                template_ref  = vm["USER_TEMPLATE/PUBLIC_CLOUD/VCENTER_REF"]
2540
                template_uuid = vm["USER_TEMPLATE/PUBLIC_CLOUD/VM_TEMPLATE"]
2541

    
2542
                # We try to check if the template's moref found inside the XML template
2543
                # is found in the templates retrieved from vcenter only once
2544
                if template_ref
2545

    
2546
                    templates_found = vc_templates[vcenter_uuid].select do |ref, value|
2547
                        template_ref == ref
2548
                    end
2549

    
2550
                    if templates_found.size != 1
2551
                        template_ref = nil
2552
                    end
2553
                end
2554

    
2555
                # Try to get moref using the templates uuid. Note that that uuid
2556
                # is not unique
2557
                templates_same_uuid = {}
2558
                if !template_ref && template_uuid
2559
                    templates_found = 0
2560
                    vc_templates[vcenter_uuid].each do |ref, value|
2561
                        if value["config.uuid"] == template_uuid
2562
                            templates_found += 1
2563
                            templates_same_uuid[ref] = value
2564
                            if templates_found > 1
2565
                                template_ref = nil
2566
                            else
2567
                                template_ref = ref
2568
                            end
2569
                        end
2570
                    end
2571
                end
2572

    
2573
                if !template_ref
2574
                    STDOUT.puts("\n\e[93mWARNING: Manual intervention required!\e[39m")
2575
                    STDOUT.puts("\nWhich vCenter template is associated with OpenNebula \e[96mVM #{vm_name}?\e[39m\n")
2576
                    STDOUT.puts
2577

    
2578
                    index = 0
2579
                    template_refs  = []
2580

    
2581
                    if templates_same_uuid.length > 1
2582
                        # Choose only between those that have the same UUID
2583
                        templates_list = templates_same_uuid
2584
                    else
2585
                        templates_list = vc_templates[vcenter_uuid]
2586
                    end
2587

    
2588
                    templates_list.each do |ref, t|
2589
                        item = RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)
2590

    
2591
                        folders = []
2592
                        while !item.instance_of? RbVmomi::VIM::Datacenter
2593
                            item = item.parent
2594
                            if !item.instance_of?(RbVmomi::VIM::Datacenter)
2595
                                if item.name != "vm"
2596
                                    folders << item.name
2597
                                else
2598
                                    folders << ""
2599
                                end
2600
                            end
2601
                            if item.nil?
2602
                                raise "Could not find the Datacenter for the template"
2603
                            end
2604
                        end
2605
                        datacenter = item
2606
                        location   = folders.reverse.join("/")
2607
                        location = "/" if location.empty?
2608

    
2609

    
2610
                        template_refs << ref
2611
                        STDOUT.puts("#{index+1}: Template #{t["name"]} in Datacenter #{datacenter.name} Location: #{location}")
2612
                        index += 1
2613
                    end
2614

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

    
2617
                    loop do
2618
                        STDOUT.print("\nFrom the list above, please \e[95mpick a number\e[39m in order to specify the venter template that this VM was based on: ")
2619
                        template_index = STDIN.gets.strip.to_i
2620
                        next if template_index == 0 || template_index - 1 < 0 || template_index > template_refs.size + 1
2621
                        template_ref  = template_refs[template_index-1] rescue nil
2622
                        break
2623
                    end
2624
                end
2625

    
2626
                STDOUT.puts
2627
                STDOUT.puts "-" * 80
2628
                STDOUT.puts
2629
            end
2630

    
2631
            if !template_ref
2632
                # This VM doesn't have an associated template any more. Let's
2633
                # treat it as a wild VM
2634
                vm_wild = true
2635
                template_ref = vm_ref
2636
            end
2637

    
2638
            # Get VM's datacenter name
2639
            dc = get_dc(vc_vmachine_object)
2640
            dc_name = dc.name
2641
            dc_ref  = dc._ref
2642

    
2643
            # Get xml template from tmp with unmanaged disks and nics and new attributes
2644
            template_id  = vm["TEMPLATE/TEMPLATE_ID"]
2645
            template_xml = nil
2646

    
2647
            if !vm_wild
2648
                template_filename = "#{TEMP_DIR}/one_migrate_template_#{template_id}"
2649
                if File.exist?("#{template_filename}")
2650
                    template_xml = File.open(template_filename) { |f| Nokogiri::XML(f, nil, "UTF-8"){|c| c.default_xml.noblanks} }
2651
                end
2652
            end
2653

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

    
2657
            # Replace VM's deploy_id uuid with moref
2658
            xml_deploy_id  = xml_doc.root.at_xpath("DEPLOY_ID")
2659
            xml_deploy_id.content = vc_vmachine_object._ref
2660

    
2661
            # Inform about the changes
2662
            STDOUT.puts "VM \e[96m#{vm_name}\e[39m:"
2663
            STDOUT.puts
2664
            STDOUT.puts "--- DEPLOY_ID has been changed to #{vc_vmachine_object._ref}"
2665

    
2666
            # Retrieve and remove disks and nics from vm
2667
            existing_disks = xml_doc.root.xpath("TEMPLATE/DISK").remove # Retrieve and remove existing disks
2668
            existing_nics  = xml_doc.root.xpath("TEMPLATE/NIC").remove  # Retrieve and remove existing nics
2669

    
2670
            # Discover existing disks and/or nics
2671
            # It will return an extraconfig for VM reconfigure
2672
            extraconfig = vm_unmanaged_discover(vc_vmachine["config.hardware.device"],
2673
                                                xml_doc,
2674
                                                template_xml,
2675
                                                existing_disks,
2676
                                                existing_nics,
2677
                                                ccr_name,
2678
                                                ccr_ref,
2679
                                                vcenter_name,
2680
                                                vcenter_uuid,
2681
                                                vcenter_user,
2682
                                                vcenter_pass,
2683
                                                vcenter_host,
2684
                                                dc_name,
2685
                                                dc_ref,
2686
                                                ipool,
2687
                                                vnpool,
2688
                                                dspool,
2689
                                                hpool,
2690
                                                one_client,
2691
                                                vi_client,
2692
                                                vm_wild,
2693
                                                vm_id,
2694
                                                vc_vmachine["name"],
2695
                                                vc_templates[vcenter_uuid],
2696
                                                vm_ref,
2697
                                                vc_vmachines[vcenter_uuid],
2698
                                                template_ref,
2699
                                                one_clusters,
2700
                                                vcenter_ids)
2701

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

    
2705
            if vm["TEMPLATE/CONTEXT/TOKEN"] == "YES"
2706
                STDOUT.puts
2707
                STDOUT.puts "VM #{vm_name} generating token.txt..."
2708
                onegate_token = vc_vmachine["config.extraConfig"].select{|val| val[:key]=="opennebula.token"}.first.value rescue nil
2709

    
2710
                # For older versions try to extract if from context inside VM
2711
                if !onegate_token
2712
                    context = vc_vmachine["config.extraConfig"].select{|val| val[:key]=="guestinfo.opennebula.context"}.first.value rescue nil
2713
                    if context
2714
                        onegate_token = Base64.decode64(context).split("\n").select{|line| line.start_with?("ONEGATE_TOKEN")}.first[/ONEGATE_TOKEN='(.*?)'/,1] rescue nil
2715
                    end
2716
                end
2717
                STDOUT.put "--- Could not extract token from vcenter vm or context section" if !onegate_token
2718
                File.open("/var/lib/one/vms/#{vm_id}/token.txt",'w'){|f| f.puts(onegate_token)}
2719
            end
2720

    
2721
            # Add opennebula.disk elements to vcenter VM so unmanaged disks are referenced
2722
            spec = {}
2723
            spec[:extraConfig]  = extraconfig if !extraconfig.empty?
2724
            vc_vmachine_object.ReconfigVM_Task(:spec => spec).wait_for_completion
2725

    
2726
            STDOUT.puts
2727
            STDOUT.puts "-" * 80
2728
            STDOUT.puts
2729
        rescue Exception => e
2730
            raise e
2731
        ensure
2732
            vi_client.vim.close if vi_client
2733
        end
2734
    end
2735
end
2736

    
2737
################################################################################
2738
# Pre-migrator tool                                                            #
2739
################################################################################
2740

    
2741
CommandParser::CmdParser.new(ARGV) do
2742
    usage "`vcenter_one54_pre` [<options>]"
2743
    description ""
2744
    version OpenNebulaHelper::ONE_VERSION
2745

    
2746
    helper=OpenNebulaHelper::OneHelper.new
2747

    
2748
    before_proc do
2749
        helper.set_client(options)
2750
    end
2751

    
2752
    cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE]
2753
    set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS
2754

    
2755
    option CommandParser::OPTIONS
2756

    
2757
    main do
2758
        begin
2759
            msg = "  vCenter pre-migrator tool for OpenNebula 5.4 - Version: 1.0"
2760
            logo_banner(msg)
2761

    
2762
            # Initialize opennebula client
2763
            one_client = OpenNebula::Client.new()
2764
            vcenter_instances = []
2765

    
2766
            hpool = OpenNebula::HostPool.new(one_client)
2767
            rc = hpool.info
2768

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

    
2771
            cpool = OpenNebula::ClusterPool.new(one_client)
2772
            rc = cpool.info
2773
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2774

    
2775
            vc_clusters   = {}
2776
            vc_datastores = {}
2777
            vc_networks   = {}
2778
            vc_vmachines  = {}
2779
            vc_templates  = {}
2780

    
2781
            banner " PHASE 0 - Before running the script please read the following notes", true
2782

    
2783
            STDOUT.puts
2784
            STDOUT.puts("- Please check that you have set PERSISTENT_ONLY=\"NO\" and REQUIRED_ATTRS=\"\"\n"\
2785
                        "  in you DS_MAD_CONF vcenter inside the /etc/one/oned.conf and that you have\n"\
2786
                        "  restarted your OpenNebula services to apply the new configuration before\n"\
2787
                        "  launching the script.")
2788
            STDOUT.puts
2789
            STDOUT.puts("- Edit the file \e[92m/var/lib/one/remotes/datastore/vcenter/rm\e[39m and replace the\n"\
2790
                        "  following lines:\n\n"\
2791
                        "  \e[96mvi_client.delete_virtual_disk(img_src,\n"\
2792
                        "                                ds_name)\e[39m \n\n"\
2793
                        "  with the following lines:\n\n"\
2794
                        "  \e[96mif drv_action[\"/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_IMPORTED\"] != \"YES\"\n"\
2795
                        "       vi_client.delete_virtual_disk(img_src,ds_name) \n"\
2796
                        "  end\e[39m \n\n"\
2797
                        "  in order to avoid that you accidentally remove a virtual hard disk from a template \n"\
2798
                        "  or wild VM when you delete an image.")
2799
            STDOUT.puts
2800
            STDOUT.puts("- Note that this script may take some time to perform complex tasks so \e[96mplease be patient.\e[39m")
2801
            STDOUT.puts
2802
            STDOUT.puts("- Although this scripts will do its best to be fully automated there may be situations\n"\
2803
                        "  where a manual intervention is needed, in that case a \e[93mWARNING\e[39m will be shown.")
2804
            STDOUT.puts
2805
            STDOUT.puts("- The virtual networks that represent port groups found inside existing templates\n"\
2806
                        "  will have an Ethernet address range with 255 MACs in the pool. You may want to\n"\
2807
                        "  change or increase this address range after the pre-migrator tool finishes.")
2808
            STDOUT.puts
2809
            STDOUT.puts("- It's advisable to disable the Sunstone user interface before launching this script\n"\
2810
                        "  in order to avoid that OpenNebula objects created by users while\n"\
2811
                        "  the script is running are not pre-migrated by the tool.")
2812
            STDOUT.puts
2813
            STDOUT.puts("- This script can be executed as many times as you wish. It will update previous\n"\
2814
                        "  results and XML template will be always overwritten.")
2815
            STDOUT.puts
2816
            STDOUT.puts("\e[93mDon't forget to restart OpenNebula if you have made changes!\e[39m")
2817

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

    
2820
            exit! if STDIN.gets.strip.downcase == 'n'
2821

    
2822
            banner " PHASE 1 - Retrieve objects from vCenter instances", true
2823

    
2824
            STDOUT.puts
2825
            STDOUT.puts "Inventory objects are being retrieved, \e[96mplease be patient...\e[39m"
2826
            STDOUT.puts
2827

    
2828
            # For each vCenter host we:
2829
            # - Create a rbvmomi connection
2830
            # - Generate views for clusters, datastores, networks and VMs
2831

    
2832
            hpool.each do |host|
2833
                next if host['VM_MAD'] != "vcenter"
2834

    
2835
                vi_client = VCenterDriver::VIClient.new(host["ID"])
2836
                vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid
2837
                if vcenter_instances.include?(vcenter_uuid)
2838
                    vi_client.vim.close
2839
                    next
2840
                end
2841
                vcenter_instances << vcenter_uuid
2842

    
2843
                # Retrieve vCenter Managed Objects
2844
                vc_clusters[vcenter_uuid]   = retrieve_vcenter_clusters(vi_client)
2845
                vc_datastores[vcenter_uuid] = retrieve_vcenter_datastores(vi_client)
2846
                vc_networks[vcenter_uuid]   = retrieve_vcenter_networks(vi_client)
2847
                vc_vmachines[vcenter_uuid], vc_templates[vcenter_uuid] = retrieve_vcenter_vms(vi_client)
2848

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

    
2852
            STDOUT.puts
2853
            STDOUT.puts "All vCenter objects have been retrieved, thanks for your patience."
2854

    
2855
            # Control what objects id have been modified
2856
            vcenter_ids = {}
2857
            vcenter_ids[:host]  = []
2858
            vcenter_ids[:ds]    = []
2859
            vcenter_ids[:vnet]  = []
2860
            vcenter_ids[:image] = []
2861

    
2862
            banner " PHASE 2 - Add new attributes to existing hosts", true
2863
            add_new_host_attrs(vc_clusters, hpool, one_client, vcenter_ids)
2864

    
2865
            banner " PHASE 3 - Create OpenNebula clusters if needed", true
2866
            STDOUT.puts
2867

    
2868
            one_clusters = create_new_clusters(vc_clusters, hpool, cpool, one_client)
2869

    
2870
            dspool = OpenNebula::DatastorePool.new(one_client)
2871
            rc = dspool.info
2872
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2873

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

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

    
2880
            extended_message = " - Add new attributes to datastores\n"\
2881
                               " - Create SYSTEM datastores if needed\n"\
2882
                               " - Assign datastores to OpenNebula Clusters"
2883

    
2884
            banner " PHASE 4 - Inspect existing datatores ", true, extended_message
2885

    
2886
            inspect_datastores(vc_datastores, vc_clusters, one_clusters, dspool, hpool, one_client, vcenter_ids)
2887

    
2888
            rc = dspool.info # Refresh datastore pool
2889
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2890

    
2891
            vnpool = OpenNebula::VirtualNetworkPool.new(one_client)
2892
            rc = vnpool.info_all
2893
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2894

    
2895
            extended_message = " - Add new attributes to vnets\n"\
2896
                               " - Assign vnets to OpenNebula Clusters"
2897
            banner " PHASE 5 - Add new attributes to existing vnets", true, extended_message
2898
            inspect_networks(vc_networks, vc_clusters, one_clusters, vnpool, hpool, one_client, vcenter_ids)
2899

    
2900
            ipool = OpenNebula::ImagePool.new(one_client)
2901
            rc = ipool.info_all
2902
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2903

    
2904
            banner " PHASE 6 - Add new attributes to existing images", true
2905
            add_new_image_attrs(ipool, one_client, vcenter_ids)
2906

    
2907
            rc = ipool.info_all
2908
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2909

    
2910
            tpool = OpenNebula::TemplatePool.new(one_client)
2911
            rc = tpool.info_all
2912
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2913

    
2914
            extended_message = " - Add new attributes to existing templates\n"\
2915
                               " - Discover nics and disks inside templates\n"\
2916
                               " - Import datastores where discovered virtual disks are found if needed.\n"\
2917
                               " - Create images for discovered virtual hard disks\n"\
2918
                               " - Create vnets for discovered port groups\n"\
2919
                               " - Prepare XML VM templates removing old or deprecated attributes\n"
2920

    
2921
            banner " PHASE 7 - Inspect existing VM templates", true, extended_message
2922

    
2923
            inspect_templates(vc_templates, vc_clusters, one_clusters, tpool, ipool, vnpool, dspool, hpool, one_client, vcenter_ids)
2924

    
2925
            vmpool = OpenNebula::VirtualMachinePool.new(one_client)
2926
            rc = vmpool.info_all
2927
            raise "Error contacting OpenNebula #{rc.message}" if OpenNebula.is_error?(rc)
2928

    
2929
            extended_message = " - Add new attributes to existing VMs\n"\
2930
                               " - Discover nics and disks inside VMs\n"\
2931
                               " - Import datastores where discovered virtual disks are found if needed.\n"\
2932
                               " - Create images for discovered virtual hard disks\n"\
2933
                               " - Create vnets for discovered port groups\n"\
2934
                               " - Prepare XML VM templates removing old or deprecated attributes\n"\
2935
                               " - Reconfigure vCenter VM to add unmanaged disks and nics references\n"\
2936
                               " - DEPLOY_ID will get VM's managed object reference\n"
2937

    
2938
            banner " PHASE 8 - Inspect existing VMs", true
2939
            STDOUT.puts
2940
            inspect_vms(vc_vmachines, vc_templates, vc_clusters, one_clusters, vmpool, ipool, tpool, vnpool, dspool, hpool, one_client, vcenter_ids)
2941

    
2942
            if !vcenter_ids[:host].empty?
2943
                banner " PHASE  9 - Prepare XML templates for hosts without deprecated attributes", true
2944
                prepare_host_xml_templates(vcenter_ids[:host], one_clusters, one_client)
2945
            end
2946

    
2947
            if !vcenter_ids[:ds].empty?
2948
                banner " PHASE 10 - Prepare XML templates for datastores without deprecated attributes", true
2949
                prepare_ds_xml_templates(vcenter_ids[:ds], one_client)
2950
            end
2951

    
2952
            if !vcenter_ids[:vnet].empty?
2953
                banner " PHASE 11 - Prepare XML templates for vnets without deprecated attributes", true
2954
                prepare_vnet_xml_templates(vcenter_ids[:vnet], one_client)
2955
            end
2956

    
2957
            if !vcenter_ids[:image].empty?
2958
                banner " PHASE 12 - Prepare XML templates for images without deprecated attributes", true
2959
                prepare_image_xml_templates(vcenter_ids[:image], hpool, one_client)
2960
            end
2961

    
2962
            puts ""
2963

    
2964
            exit_code 0
2965
        rescue Exception => e
2966
            STDERR.puts "An error occurred when pre-migrating OpenNebula:\n"\
2967
                        "#{e.message}\"\n#{e.backtrace}"
2968
            exit -1
2969
        end
2970
    end
2971
end