manageiq-smartstate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +4 -0
- data/.rspec_ci +4 -0
- data/.travis.yml +15 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +202 -0
- data/README.md +45 -0
- data/Rakefile +23 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
- data/lib/MiqVm/MiqLocalVm.rb +50 -0
- data/lib/MiqVm/MiqRhevmVm.rb +179 -0
- data/lib/MiqVm/MiqVm.rb +355 -0
- data/lib/MiqVm/miq_azure_vm.rb +96 -0
- data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
- data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
- data/lib/MiqVm/test/localVm.rb +45 -0
- data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
- data/lib/MiqVm/test/remoteVm.rb +65 -0
- data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
- data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
- data/lib/MiqVm/test/rhevmTest.rb +70 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
- data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
- data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
- data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
- data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
- data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
- data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
- data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
- data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
- data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
- data/lib/VolumeManager/LVM/parser.rb +138 -0
- data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
- data/lib/VolumeManager/LVM/scanner.rb +156 -0
- data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
- data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
- data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
- data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
- data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
- data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
- data/lib/VolumeManager/LVM/thin.rb +6 -0
- data/lib/VolumeManager/LVM/volume_group.rb +97 -0
- data/lib/VolumeManager/LVM.rb +8 -0
- data/lib/VolumeManager/MiqLdm.rb +546 -0
- data/lib/VolumeManager/MiqLvm.rb +17 -0
- data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
- data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
- data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
- data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
- data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
- data/lib/VolumeManager/test/blockDevTest.rb +40 -0
- data/lib/VolumeManager/test/ldm.rb +97 -0
- data/lib/blackbox/VmBlackBox.rb +103 -0
- data/lib/blackbox/xmlStorage.rb +180 -0
- data/lib/db/MiqBdb/MiqBdb.rb +309 -0
- data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
- data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
- data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
- data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
- data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
- data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
- data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
- data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
- data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
- data/lib/disk/DiskProbe.rb +68 -0
- data/lib/disk/MiqDisk.rb +317 -0
- data/lib/disk/camcorder_test.rb +90 -0
- data/lib/disk/dos_mbr.img +0 -0
- data/lib/disk/modules/AzureBlobDisk.rb +101 -0
- data/lib/disk/modules/LocalDevMod.rb +47 -0
- data/lib/disk/modules/LocalDevProbe.rb +6 -0
- data/lib/disk/modules/MSCommon.rb +352 -0
- data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
- data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
- data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
- data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
- data/lib/disk/modules/MiqLargeFile.rb +63 -0
- data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
- data/lib/disk/modules/QcowDisk.rb +692 -0
- data/lib/disk/modules/QcowDiskProbe.rb +34 -0
- data/lib/disk/modules/RawBlockIO.rb +116 -0
- data/lib/disk/modules/RawDisk.rb +45 -0
- data/lib/disk/modules/RawDiskProbe.rb +7 -0
- data/lib/disk/modules/RhevmDescriptor.rb +167 -0
- data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
- data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
- data/lib/disk/modules/VMWareDescriptor.rb +214 -0
- data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
- data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
- data/lib/disk/modules/VhdxDisk.rb +625 -0
- data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
- data/lib/disk/modules/VixDiskMod.rb +54 -0
- data/lib/disk/modules/VixDiskProbe.rb +6 -0
- data/lib/disk/modules/miq_disk_cache.rb +135 -0
- data/lib/disk/modules/miq_dummy_disk.rb +41 -0
- data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
- data/lib/disk/test.rb +66 -0
- data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
- data/lib/fs/MetakitFS/test/Makefile +14 -0
- data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
- data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
- data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
- data/lib/fs/MetakitFS/test/init.rb +3 -0
- data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
- data/lib/fs/MetakitFS/test/mk4test.c +92 -0
- data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
- data/lib/fs/MetakitFS/test/proto.rb +97 -0
- data/lib/fs/MiqFS/FsProbe.rb +39 -0
- data/lib/fs/MiqFS/MiqFS.rb +515 -0
- data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
- data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
- data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
- data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
- data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
- data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
- data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
- data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
- data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
- data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
- data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
- data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
- data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
- data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
- data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
- data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
- data/lib/fs/MiqFS/modules/XFS.rb +300 -0
- data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
- data/lib/fs/MiqFS/test.rb +59 -0
- data/lib/fs/MiqFsUtil.rb +383 -0
- data/lib/fs/MiqMountManager.rb +209 -0
- data/lib/fs/MiqNativeMountManager.rb +101 -0
- data/lib/fs/MountManagerProbe.rb +29 -0
- data/lib/fs/ReiserFS/block.rb +209 -0
- data/lib/fs/ReiserFS/directory.rb +136 -0
- data/lib/fs/ReiserFS/directory_entry.rb +140 -0
- data/lib/fs/ReiserFS/file_data.rb +111 -0
- data/lib/fs/ReiserFS/superblock.rb +140 -0
- data/lib/fs/ReiserFS/utils.rb +95 -0
- data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
- data/lib/fs/ext3/alloc_bitmap.rb +38 -0
- data/lib/fs/ext3/block_pointers_path.rb +130 -0
- data/lib/fs/ext3/directory.rb +51 -0
- data/lib/fs/ext3/directory_entry.rb +67 -0
- data/lib/fs/ext3/ex_attrib_header.rb +14 -0
- data/lib/fs/ext3/ex_attrib_name.rb +23 -0
- data/lib/fs/ext3/file_data.rb +130 -0
- data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
- data/lib/fs/ext3/group_descriptor_table.rb +54 -0
- data/lib/fs/ext3/hash_tree_entry.rb +18 -0
- data/lib/fs/ext3/hash_tree_header.rb +15 -0
- data/lib/fs/ext3/inode.rb +228 -0
- data/lib/fs/ext3/posix_acl_entry.rb +29 -0
- data/lib/fs/ext3/posix_acl_header.rb +11 -0
- data/lib/fs/ext3/superblock.rb +406 -0
- data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
- data/lib/fs/ext4/alloc_bitmap.rb +38 -0
- data/lib/fs/ext4/directory.rb +87 -0
- data/lib/fs/ext4/directory_entry.rb +77 -0
- data/lib/fs/ext4/ex_attrib_header.rb +14 -0
- data/lib/fs/ext4/ex_attrib_name.rb +23 -0
- data/lib/fs/ext4/extent.rb +35 -0
- data/lib/fs/ext4/extent_header.rb +40 -0
- data/lib/fs/ext4/extent_index.rb +33 -0
- data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
- data/lib/fs/ext4/group_descriptor_table.rb +54 -0
- data/lib/fs/ext4/hash_tree_entry.rb +58 -0
- data/lib/fs/ext4/hash_tree_header.rb +35 -0
- data/lib/fs/ext4/inode.rb +465 -0
- data/lib/fs/ext4/posix_acl_entry.rb +29 -0
- data/lib/fs/ext4/posix_acl_header.rb +11 -0
- data/lib/fs/ext4/superblock.rb +412 -0
- data/lib/fs/fat32/boot_sect.rb +379 -0
- data/lib/fs/fat32/directory.rb +222 -0
- data/lib/fs/fat32/directory_entry.rb +540 -0
- data/lib/fs/fat32/file_data.rb +128 -0
- data/lib/fs/iso9660/boot_sector.rb +170 -0
- data/lib/fs/iso9660/directory.rb +90 -0
- data/lib/fs/iso9660/directory_entry.rb +147 -0
- data/lib/fs/iso9660/file_data.rb +78 -0
- data/lib/fs/iso9660/rock_ridge.rb +329 -0
- data/lib/fs/iso9660/util.rb +57 -0
- data/lib/fs/modules/LinuxMount.rb +300 -0
- data/lib/fs/modules/LinuxMountProbe.rb +29 -0
- data/lib/fs/modules/WinMount.rb +97 -0
- data/lib/fs/modules/WinMountProbe.rb +24 -0
- data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
- data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
- data/lib/fs/ntfs/attrib_data.rb +74 -0
- data/lib/fs/ntfs/attrib_file_name.rb +110 -0
- data/lib/fs/ntfs/attrib_header.rb +194 -0
- data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
- data/lib/fs/ntfs/attrib_index_root.rb +247 -0
- data/lib/fs/ntfs/attrib_object_id.rb +40 -0
- data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
- data/lib/fs/ntfs/attrib_type.rb +49 -0
- data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
- data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
- data/lib/fs/ntfs/boot_sect.rb +253 -0
- data/lib/fs/ntfs/data_run.rb +358 -0
- data/lib/fs/ntfs/directory_index_node.rb +114 -0
- data/lib/fs/ntfs/index_node_header.rb +69 -0
- data/lib/fs/ntfs/index_record_header.rb +85 -0
- data/lib/fs/ntfs/mft_entry.rb +288 -0
- data/lib/fs/ntfs/utils.rb +43 -0
- data/lib/fs/test/camcorder_fs_test.rb +108 -0
- data/lib/fs/test/collect_files_direct.yaml +22 -0
- data/lib/fs/test/collect_files_in.yaml +24 -0
- data/lib/fs/test/collect_files_in_nc.yaml +22 -0
- data/lib/fs/test/collect_files_out.yaml +6 -0
- data/lib/fs/test/collect_files_rm.yaml +6 -0
- data/lib/fs/test/copyTest.rb +126 -0
- data/lib/fs/test/fsTest.rb +87 -0
- data/lib/fs/test/updateTest.rb +184 -0
- data/lib/fs/xfs/allocation_group.rb +160 -0
- data/lib/fs/xfs/bmap_btree_block.rb +125 -0
- data/lib/fs/xfs/bmap_btree_record.rb +80 -0
- data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
- data/lib/fs/xfs/directory.rb +133 -0
- data/lib/fs/xfs/directory2_data_header.rb +27 -0
- data/lib/fs/xfs/directory3_data_header.rb +34 -0
- data/lib/fs/xfs/directory_block_tail.rb +22 -0
- data/lib/fs/xfs/directory_data_header.rb +46 -0
- data/lib/fs/xfs/directory_entry.rb +106 -0
- data/lib/fs/xfs/inode.rb +532 -0
- data/lib/fs/xfs/inode_map.rb +100 -0
- data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
- data/lib/fs/xfs/short_form_header.rb +44 -0
- data/lib/fs/xfs/superblock.rb +556 -0
- data/lib/lib/tasks/azure.rake +52 -0
- data/lib/manageiq/smartstate/version.rb +5 -0
- data/lib/manageiq/smartstate.rb +7 -0
- data/lib/manageiq-smartstate.rb +1 -0
- data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
- data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
- data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
- data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
- data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
- data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
- data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
- data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
- data/lib/metadata/VMMount/VMMount.rb +81 -0
- data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
- data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
- data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
- data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
- data/lib/metadata/VmConfig/VmConfig.rb +947 -0
- data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
- data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
- data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
- data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
- data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
- data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
- data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
- data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
- data/lib/metadata/linux/InitProcHash.rb +632 -0
- data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
- data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
- data/lib/metadata/linux/LinuxPackages.rb +209 -0
- data/lib/metadata/linux/LinuxSystemd.rb +130 -0
- data/lib/metadata/linux/LinuxUsers.rb +289 -0
- data/lib/metadata/linux/LinuxUtils.rb +197 -0
- data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
- data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
- data/lib/metadata/linux/test/Name +0 -0
- data/lib/metadata/linux/test/Packages +0 -0
- data/lib/metadata/linux/test/rpoTest.rb +5 -0
- data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
- data/lib/metadata/util/event_log_filter.rb +61 -0
- data/lib/metadata/util/md5deep.rb +280 -0
- data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
- data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
- data/lib/metadata/util/win32/Win32Services.rb +86 -0
- data/lib/metadata/util/win32/Win32Software.rb +326 -0
- data/lib/metadata/util/win32/Win32System.rb +333 -0
- data/lib/metadata/util/win32/boot_info_win.rb +59 -0
- data/lib/metadata/util/win32/fleece_hives.rb +220 -0
- data/lib/metadata/util/win32/ms-registry.rb +650 -0
- data/lib/metadata/util/win32/peheader.rb +868 -0
- data/lib/metadata/util/win32/remote-registry.rb +142 -0
- data/lib/metadata/util/win32/system_path_win.rb +103 -0
- data/lib/metadata/util/win32/versioninfo.rb +17 -0
- data/manageiq-smartstate.gemspec +35 -0
- metadata +486 -0
@@ -0,0 +1,947 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'metadata/VMMount/VMMount'
|
3
|
+
require 'util/miq-unicode'
|
4
|
+
require 'util/miq-xml'
|
5
|
+
require 'VMwareWebService/MiqVimInventory'
|
6
|
+
require 'timeout'
|
7
|
+
require 'util/miq-extensions'
|
8
|
+
require 'VMwareWebService/MiqVimBroker'
|
9
|
+
|
10
|
+
class VmConfig
|
11
|
+
attr_reader :configFile
|
12
|
+
|
13
|
+
def initialize(filename)
|
14
|
+
@configFile = nil
|
15
|
+
@configPath = nil
|
16
|
+
@direct_file_access = true
|
17
|
+
|
18
|
+
if filename.kind_of? Hash
|
19
|
+
@direct_file_access = false
|
20
|
+
@cfgHash = filename
|
21
|
+
else
|
22
|
+
@cfgHash = {}
|
23
|
+
# If filename contains embedded new-line chars treat it as data. Otherwise, its a filename.
|
24
|
+
if filename.index("\n")
|
25
|
+
f = filename
|
26
|
+
else
|
27
|
+
set_vmconfig_path(filename)
|
28
|
+
|
29
|
+
begin
|
30
|
+
configType = File.extname(filename).delete(".").downcase
|
31
|
+
require "metadata/VmConfig/#{configType}Config"
|
32
|
+
rescue LoadError => e
|
33
|
+
raise e, "Filetype unrecognized for file #{filename}"
|
34
|
+
end
|
35
|
+
extend Kernel.const_get(configType.capitalize + "Config")
|
36
|
+
f = convert(filename)
|
37
|
+
end
|
38
|
+
|
39
|
+
process_file(f)
|
40
|
+
|
41
|
+
f.close if f.class == File
|
42
|
+
|
43
|
+
postProcessDisks
|
44
|
+
end
|
45
|
+
|
46
|
+
# Handle oddities
|
47
|
+
configuration_fixup
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_file(data_lines)
|
51
|
+
data_lines.each_line do |line|
|
52
|
+
line.AsciiToUtf8!.strip!
|
53
|
+
next if line.length == 0
|
54
|
+
next if line =~ /^#.*$/
|
55
|
+
next unless line.include?("=")
|
56
|
+
k, v = line.split(/\s*=\s*/)
|
57
|
+
|
58
|
+
# Note: All key names are lower-cased for easy lookup
|
59
|
+
k = k.downcase
|
60
|
+
v = v.gsub(/^"/, "").gsub(/"$/, "")
|
61
|
+
|
62
|
+
@cfgHash[k] = v
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def postProcessDisks
|
67
|
+
# Convert absolute paths to relative paths for the disks
|
68
|
+
if @direct_file_access
|
69
|
+
getAllDiskKeys.each do |dk|
|
70
|
+
next if @cfgHash[dk + ".devicetype"] && @cfgHash[dk + ".devicetype"].include?("cdrom")
|
71
|
+
next if @cfgHash[dk + ".filename"] && @cfgHash[dk + ".filename"].downcase == "auto detect"
|
72
|
+
|
73
|
+
begin
|
74
|
+
dskPath = Pathname.new(@cfgHash[dk + ".filename"])
|
75
|
+
begin
|
76
|
+
@cfgHash[dk + ".filename"] = dskPath.relative_path_from(Pathname.new(@configPath)).to_s.tr("\\", "/") if dskPath.absolute?
|
77
|
+
rescue
|
78
|
+
@cfgHash[dk + ".filename"] = dskPath.to_s.tr("\\", "/")
|
79
|
+
end
|
80
|
+
if self.respond_to?(:diskCreateType)
|
81
|
+
createType = diskCreateType(@cfgHash[dk + ".filename"])
|
82
|
+
@cfgHash[dk + ".createType"] = createType if createType
|
83
|
+
end
|
84
|
+
if self.respond_to?(:diskControllerType)
|
85
|
+
adapterType = diskControllerType(@cfgHash[dk + ".filename"])
|
86
|
+
@cfgHash[dk + ".adapterType"] = adapterType if adapterType
|
87
|
+
end
|
88
|
+
rescue => err
|
89
|
+
$log.warn "VmConfig: Failed to convert path: #{@cfgHash[dk + ".filename"]}, #{err}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def getHash
|
96
|
+
@cfgHash
|
97
|
+
end
|
98
|
+
|
99
|
+
def getDiskFileHash
|
100
|
+
return @diskFileHash if @diskFileHash
|
101
|
+
|
102
|
+
@diskFileHash = {}
|
103
|
+
getAllDiskKeys.each do |dk|
|
104
|
+
next if @cfgHash[dk + ".devicetype"] && @cfgHash[dk + ".devicetype"].include?("cdrom")
|
105
|
+
next if @cfgHash[dk + ".filename"] && @cfgHash[dk + ".filename"].downcase == "auto detect"
|
106
|
+
filename = @cfgHash[dk + ".filename"]
|
107
|
+
@diskFileHash[dk] = filename
|
108
|
+
if @direct_file_access
|
109
|
+
ds, _dir, _name = split_filename(filename)
|
110
|
+
if ds.nil? && !Pathname.new(filename).absolute?
|
111
|
+
@diskFileHash[dk] = File.expand_path(File.join(@configPath, filename))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
@diskFileHash
|
116
|
+
end # getDiskFileHash
|
117
|
+
|
118
|
+
def getAllDiskKeys
|
119
|
+
dskKeys = @cfgHash.keys.delete_if { |e| !diskKey?(e) }.collect! { |e| e.gsub(".filename", "") }
|
120
|
+
dskKeys.delete_if { |dk| @cfgHash[dk + ".present"].to_s.downcase == "false" }
|
121
|
+
dskKeys.sort
|
122
|
+
end
|
123
|
+
|
124
|
+
def getSnapshotDiskFileHash
|
125
|
+
return @snapshotdiskFileHash if @snapshotdiskFileHash
|
126
|
+
|
127
|
+
# For snapshots we need to keep the disks order by snapshot uid, then by device
|
128
|
+
@snapshotdiskFileHash = Hash.new { |h, k| h[k] = {} }
|
129
|
+
getSnapshotDiskKeys.each do |dk|
|
130
|
+
next if @cfgHash[dk + ".devicetype"].to_s.include?("cdrom")
|
131
|
+
next if @cfgHash[dk + ".filename"].to_s.downcase == "auto detect"
|
132
|
+
dk =~ /^snapshot\d+/
|
133
|
+
sn_uid = @cfgHash["#{$&}.uid"]
|
134
|
+
key = @cfgHash[dk + ".node"]
|
135
|
+
|
136
|
+
# Independent disks do not par-take in snapshots. Check the mode of the parent disk.
|
137
|
+
next if @cfgHash["#{key}.mode"].to_s.include?('independent')
|
138
|
+
|
139
|
+
@snapshotdiskFileHash[sn_uid]['disks'] ||= {}
|
140
|
+
filename = @cfgHash[dk + ".filename"]
|
141
|
+
disk_path = filename
|
142
|
+
|
143
|
+
if @direct_file_access
|
144
|
+
ds, _dir, _name = split_filename(filename)
|
145
|
+
if ds.nil? && !Pathname.new(@cfgHash[dk + ".filename"]).absolute?
|
146
|
+
disk_path = File.join(@configPath, filename)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
@snapshotdiskFileHash[sn_uid]['disks'][key] = disk_path
|
150
|
+
end
|
151
|
+
@snapshotdiskFileHash
|
152
|
+
end # getSnapshotDiskFileHash
|
153
|
+
|
154
|
+
def getSnapshotDiskKeys
|
155
|
+
dskKeys = @cfgHash.keys.delete_if { |e| !snapshotdiskKey?(e) }.collect! { |e| e.gsub(".filename", "") }
|
156
|
+
dskKeys.delete_if { |dk| @cfgHash[dk + ".present"].to_s.downcase == "false" }
|
157
|
+
dskKeys.sort
|
158
|
+
end
|
159
|
+
|
160
|
+
def set_vmconfig_path(config_path)
|
161
|
+
ds, _dir, _name = split_filename(config_path)
|
162
|
+
@configFile = ds.nil? ? File.normalize(config_path) : config_path
|
163
|
+
@configPath = File.dirname(@configFile)
|
164
|
+
end
|
165
|
+
|
166
|
+
def to_xml(diskStats = true, miqvm = nil)
|
167
|
+
# If loaded directly from a hash object, try to add snapshot metadata before processing
|
168
|
+
load_vim_snapshots(miqvm)
|
169
|
+
|
170
|
+
set_vmconfig_path(miqvm.vmConfigFile) unless miqvm.nil?
|
171
|
+
|
172
|
+
normalize_file_paths
|
173
|
+
|
174
|
+
xml = MiqXml.createDoc("<vm_configuration><hardware></hardware><vm/></vm_configuration>", "vendor" => vendor)
|
175
|
+
# Sort the Hash into an array to group like keys and add each array to the XML doc
|
176
|
+
@cfgHash.sort { |a, b| a <=> b }.each do |(k, v)|
|
177
|
+
next if k[0..0] == '.'
|
178
|
+
insert_XML(k, v, xml)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Pre-load data
|
182
|
+
unless miqvm.nil?
|
183
|
+
# Make sure we have the volume manager and loaded
|
184
|
+
begin
|
185
|
+
miqvm.rootTrees[0]
|
186
|
+
@vol_mgr_loaded = true
|
187
|
+
rescue LoadError
|
188
|
+
$log.warn "add_disk_stats [#{$!.class}]-[#{$!}]"
|
189
|
+
end
|
190
|
+
|
191
|
+
files(miqvm)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Add virtual disk sizes
|
195
|
+
add_disk_stats(xml, miqvm) if diskStats
|
196
|
+
|
197
|
+
# Here we list all files in the directory and get their size on disk.
|
198
|
+
add_file_sizes(xml, miqvm)
|
199
|
+
|
200
|
+
# Add partition and volume information
|
201
|
+
add_volumes(xml, miqvm)
|
202
|
+
|
203
|
+
# Add date and size info for snapshots
|
204
|
+
add_snapshot_size(xml, miqvm)
|
205
|
+
|
206
|
+
# TODO: Re-enable
|
207
|
+
# normalize_path_names(xml)
|
208
|
+
|
209
|
+
xml
|
210
|
+
end
|
211
|
+
|
212
|
+
alias_method :toXML, :to_xml
|
213
|
+
|
214
|
+
def getDriveImageList
|
215
|
+
vmDisks = []
|
216
|
+
# Convert config file to XML
|
217
|
+
xml = toXML(false)
|
218
|
+
# Find the disk section of the XML
|
219
|
+
xml.root.each_recursive do |e|
|
220
|
+
# Only process drives that are present and have a filename
|
221
|
+
if (!e.attributes['present'].nil? && e.attributes['present'].downcase == 'true') && !e.attributes['filename'].nil? && (!e.attributes['type'].nil? && e.attributes['type'].downcase == 'disk') && (!e.attributes['id'].nil? && e.attributes['id'].include?(":"))
|
222
|
+
# Make sure the disk we are looking at is not a CD-ROM
|
223
|
+
if e.attributes['devicetype'].nil? || (!e.attributes['devicetype'].nil? && e.attributes['devicetype'].downcase.index("cd").nil?)
|
224
|
+
diskName = e.attributes['filename'].tr("\"", "").strip.tr("\\", "/")
|
225
|
+
diskName = File.join(@configPath, diskName) unless diskName[0..0] == "/"
|
226
|
+
$log.debug "Adding Disk name to list: [#{diskName}]"
|
227
|
+
begin
|
228
|
+
vmDisks.push(File.expand_path(diskName))
|
229
|
+
rescue
|
230
|
+
vmDisks.push(diskName)
|
231
|
+
end
|
232
|
+
$log.debug "Adding Disk name to list: [#{diskName}]"
|
233
|
+
# $log.info "vmDisk Array = #{vmDisks.to_s()}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
vmDisks
|
238
|
+
end
|
239
|
+
|
240
|
+
def dump_config_to_log(log_level = :warn)
|
241
|
+
$log.send(log_level, "VmConfig: Start of configuration info for: #{@configFile}")
|
242
|
+
@cfgHash.each { |k, v| $log.send(log_level, "#{k} = #{v}") }
|
243
|
+
$log.send(log_level, "VmConfig: End of configuration info for: #{@configFile}")
|
244
|
+
end
|
245
|
+
|
246
|
+
def vendor
|
247
|
+
"unknown"
|
248
|
+
end
|
249
|
+
|
250
|
+
def find_file(filename, file_list = files)
|
251
|
+
# basename = File.basename(filename)
|
252
|
+
# return file_list.detect {|f| f[:name] == basename}
|
253
|
+
file_list.detect { |f| f[:path] == filename }
|
254
|
+
end
|
255
|
+
|
256
|
+
private
|
257
|
+
|
258
|
+
def diskKey?(key)
|
259
|
+
key =~ /^ide\d+:\d+\.filename$/ || key =~ /^scsi\d+:\d+\.filename$/
|
260
|
+
end
|
261
|
+
|
262
|
+
def snapshotdiskKey?(key)
|
263
|
+
key =~ /^snapshot\d+.disk\d+.filename$/
|
264
|
+
end
|
265
|
+
|
266
|
+
def insert_XML(key, value, xml)
|
267
|
+
maj, min, other = key.split(".")
|
268
|
+
|
269
|
+
# Any elements that cannot be split are put into a misc class
|
270
|
+
min, maj = maj, maj if min.nil?
|
271
|
+
|
272
|
+
if maj.index(/\d/)
|
273
|
+
maj_name = $`.chomp(':')
|
274
|
+
else
|
275
|
+
maj_name = maj
|
276
|
+
end
|
277
|
+
if min[0...3] == "mem" || min[0...5] == "nvram"
|
278
|
+
path = [["hardware"], ["memory"]]
|
279
|
+
elsif maj_name == "uuid"
|
280
|
+
path = [["hardware"], ["bios"]]
|
281
|
+
# Drives
|
282
|
+
elsif maj_name == "scsi" || maj_name == "ide" || maj_name == "floppy"
|
283
|
+
path = getDevicePath(maj, "disk")
|
284
|
+
# Ports
|
285
|
+
elsif maj_name == "usb" || maj_name == "parallel" || maj_name == "serial" || maj_name == "sound" || maj_name == "ethernet"
|
286
|
+
path = getDevicePath(maj, maj_name)
|
287
|
+
elsif maj_name == "snapshot"
|
288
|
+
other, min = min, other if other
|
289
|
+
path = getSnapShotPath(maj, maj_name, other)
|
290
|
+
else
|
291
|
+
path = [["vm"], [maj]]
|
292
|
+
end
|
293
|
+
|
294
|
+
parent = xml.root
|
295
|
+
path.each do |p|
|
296
|
+
if p[1].nil?
|
297
|
+
ele = MIQRexml.findElement(p[0], parent) if parent.has_elements?
|
298
|
+
else
|
299
|
+
ele = find_with_attributes(p[0], p[1], parent) if parent.has_elements?
|
300
|
+
end
|
301
|
+
|
302
|
+
# Create new node if needed.
|
303
|
+
if ele.nil?
|
304
|
+
# Remove any nil keys from the hash
|
305
|
+
p[1].delete_if { |_k, v| v.nil? } if p[1].kind_of?(Hash)
|
306
|
+
parent = parent.add_element(p[0], p[1])
|
307
|
+
else
|
308
|
+
parent, ele = ele, nil
|
309
|
+
end
|
310
|
+
end
|
311
|
+
parent.add_attribute(min.tr(':', '_'), value) if parent
|
312
|
+
end
|
313
|
+
|
314
|
+
def add_disk_stats(xml, miqvm)
|
315
|
+
# Now loop over the xml and find disk files
|
316
|
+
xml.find_first("/*/hardware").each_recursive do |e|
|
317
|
+
# Find elements that have a filename attribute
|
318
|
+
# Loop through the "whole disks" and get the size for this disk
|
319
|
+
if e.attributes['filename']
|
320
|
+
getDiskFileHash.each_pair do |device_id, filename|
|
321
|
+
if is_same_disk?(device_id, e)
|
322
|
+
if (fstat = find_file(e.attributes['filename'], disk_files(miqvm))).nil?
|
323
|
+
$log.warn "add_disk_stats - Disk file not found - Details: device_id: [#{device_id}] [#{filename}]"
|
324
|
+
next
|
325
|
+
end
|
326
|
+
|
327
|
+
$log.info "add_disk_stats - device_id: [#{device_id}] [#{filename}]"
|
328
|
+
|
329
|
+
whole_disk = nil
|
330
|
+
whole_disk = miqvm.wholeDisks.detect { |wd| wd.hwId.include?(device_id) } if @vol_mgr_loaded
|
331
|
+
size = whole_disk.nil? ? fstat[:provision_size] : whole_disk.size
|
332
|
+
|
333
|
+
# Report a disk's size_on_disk as the size of all the files that make up the disk.
|
334
|
+
# This includes the base disk and snapshots.
|
335
|
+
collective_disk_size = collective_size_on_disk(device_id, disk_files(miqvm))
|
336
|
+
size_on_disk = collective_disk_size.blank? ? fstat[:size] : collective_disk_size
|
337
|
+
e.add_attributes({'size' => size, 'size_on_disk' => size_on_disk, 'disk_type' => fstat[:disk_type]})
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
rescue Exception
|
343
|
+
$log.error "VmConfig.add_disk_stats [#{$!.class}]-[#{$!}]\n#{$!.backtrace.join("\n")}"
|
344
|
+
end
|
345
|
+
|
346
|
+
# Match filenames to loaded disks using the hardware id. IE scsi0:0 or ide0:0
|
347
|
+
def is_same_disk?(hardware_id, xml_element)
|
348
|
+
diskId = xml_element.parent.attributes["type"] + xml_element.attributes["id"].to_s
|
349
|
+
hardware_id.include?(diskId)
|
350
|
+
end
|
351
|
+
|
352
|
+
def normalize_path_names(xml)
|
353
|
+
# Now loop over the xml and find disk files
|
354
|
+
xml.root.each_recursive { |e| e.add_attribute('filename', resolve_ds_path(e.attributes['filename'])) if e.attributes['filename'] }
|
355
|
+
xml.find_first("/*/files").each_recursive { |e| e.add_attribute('name', resolve_ds_path(e.attributes['name'])) if e.attributes['name'] }
|
356
|
+
xml.find_first("/*/volumes").each_recursive { |e| e.add_attribute('virtual_disk_file', resolve_ds_path(e.attributes['virtual_disk_file'])) if e.attributes['virtual_disk_file'] }
|
357
|
+
end
|
358
|
+
|
359
|
+
def resolve_ds_path(filename)
|
360
|
+
# TODO: Determine if we need to do any work here.
|
361
|
+
ds, dir, name = split_filename(filename)
|
362
|
+
return filename unless ds.nil?
|
363
|
+
|
364
|
+
@ds_replace ||= {}
|
365
|
+
@ds_replace.each_pair do |path, ds|
|
366
|
+
return filename.sub(path, ds) if filename.include?(path)
|
367
|
+
end
|
368
|
+
|
369
|
+
ds_filename = resolve_ds_path_with_vim(filename)
|
370
|
+
ds, dir, name = split_filename(ds_filename)
|
371
|
+
unless ds.nil?
|
372
|
+
idx = filename.index(dir)
|
373
|
+
replaced_str = filename[0, idx]
|
374
|
+
@ds_replace[replaced_str] = "[#{ds}] "
|
375
|
+
end
|
376
|
+
|
377
|
+
ds_filename
|
378
|
+
end
|
379
|
+
|
380
|
+
def host_vim_credentials
|
381
|
+
creds = nil
|
382
|
+
if $miqHostCfg
|
383
|
+
if $miqHostCfg.emsLocal
|
384
|
+
creds = $miqHostCfg.ems[$miqHostCfg.emsLocal]
|
385
|
+
elsif $miqHostCfg.vimHost
|
386
|
+
c = $miqHostCfg.vimHost
|
387
|
+
return nil if c[:username].nil?
|
388
|
+
creds = {'host' => c[:address], 'user' => c[:username], 'password' => c[:password], 'use_vim_broker' => c[:use_vim_broker]}
|
389
|
+
end
|
390
|
+
end
|
391
|
+
creds
|
392
|
+
end
|
393
|
+
|
394
|
+
def connect_to_host_vim(conn_reason, vmCfgFile)
|
395
|
+
ems_host = host_vim_credentials
|
396
|
+
return nil if ems_host.nil?
|
397
|
+
|
398
|
+
begin
|
399
|
+
st = Time.now
|
400
|
+
ems_display_text = "host(#{ems_host['use_vim_broker'] ? 'via broker' : 'directly'}):#{ems_host['host']}"
|
401
|
+
$log.info "#{conn_reason}: Connecting to [#{ems_display_text}] for VM:[#{vmCfgFile}]"
|
402
|
+
|
403
|
+
require 'VMwareWebService/miq_fault_tolerant_vim'
|
404
|
+
|
405
|
+
password_decrypt = MiqPassword.decrypt(ems_host['password'])
|
406
|
+
hostVim = MiqFaultTolerantVim.new(:ip => ems_host['host'], :user => ems_host['user'], :pass => password_decrypt, :use_broker => ems_host['use_vim_broker'], :vim_broker_drb_port => ems_host['vim_broker_drb_port'])
|
407
|
+
$log.info "#{conn_reason}: Connection to [#{ems_display_text}] completed for VM:[#{vmCfgFile}] in [#{Time.now - st}] seconds"
|
408
|
+
return hostVim
|
409
|
+
rescue Timeout::Error => err
|
410
|
+
$log.error "#{conn_reason}: Connection to [#{ems_display_text}] timed out for VM:[#{vmCfgFile}] with error [#{err}] after [#{Time.now - st}] seconds"
|
411
|
+
rescue Exception => err
|
412
|
+
$log.error "#{conn_reason}: Connection to [#{ems_display_text}] failed for VM:[#{vmCfgFile}] with error [#{err}] after [#{Time.now - st}] seconds"
|
413
|
+
end
|
414
|
+
nil
|
415
|
+
end
|
416
|
+
|
417
|
+
def resolve_ds_path_with_vim(filename)
|
418
|
+
vi = nil
|
419
|
+
ems = host_vim_credentials
|
420
|
+
return (filename) if ems.nil?
|
421
|
+
|
422
|
+
password_decrypt = MiqPassword.decrypt(ems['password'])
|
423
|
+
$log.debug "resolve_path_names: emsHost = #{ems['host']}, emsUser = #{ems['user']}" if $log
|
424
|
+
vi = MiqVimInventory.new(ems['host'], ems['user'], password_decrypt)
|
425
|
+
return getDsName(filename, vi)
|
426
|
+
|
427
|
+
rescue
|
428
|
+
$log.error "VmConfig.resolve_ds_path_with_vim #{$!}\n#{$!.backtrace.join("\n")}"
|
429
|
+
ensure
|
430
|
+
vi.disconnect if vi
|
431
|
+
end
|
432
|
+
|
433
|
+
def getDsName(filename, vi)
|
434
|
+
filename = File.join(File.dirname(@configFile), filename) if File.dirname(filename) == "."
|
435
|
+
dsName = vi.datastorePath(filename)
|
436
|
+
dsName.sub!("] /", "] ") if dsName.index("] /")
|
437
|
+
return dsName
|
438
|
+
rescue
|
439
|
+
return filename
|
440
|
+
end
|
441
|
+
|
442
|
+
def files(miqvm = nil)
|
443
|
+
return @files if @files
|
444
|
+
log_header = "VmConfig.files"
|
445
|
+
|
446
|
+
@files = []
|
447
|
+
if @direct_file_access
|
448
|
+
Dir.glob(File.join(@configPath, "/*.*")) do |f|
|
449
|
+
s = File.sizeEx(f) rescue 0
|
450
|
+
@files << {:path => f, :name => File.basename(f), :size => s, :mtime => File.mtime(f)}
|
451
|
+
end
|
452
|
+
else
|
453
|
+
begin
|
454
|
+
if miqvm.vim
|
455
|
+
filePattern = nil
|
456
|
+
pathOnly = false
|
457
|
+
vimDs = nil
|
458
|
+
each_datastore(miqvm) do |ds, dirs|
|
459
|
+
begin
|
460
|
+
vimDs = miqvm.vim.getVimDataStore(ds)
|
461
|
+
dirs.each do |path|
|
462
|
+
vimDs.dsFileSearch(filePattern, path, pathOnly).each do |f|
|
463
|
+
@files << {:path => f['fullPath'], :name => f['path'], :size => f['fileSize'].to_i, :mtime => Time.parse(f['modification'])}
|
464
|
+
end
|
465
|
+
end
|
466
|
+
ensure
|
467
|
+
vimDs.release if vimDs rescue nil
|
468
|
+
end
|
469
|
+
end
|
470
|
+
elsif miqvm.rhevm
|
471
|
+
# First add the VM's active disk files.
|
472
|
+
miqvm.rhevmVm.disks.each { |disk| @files << rhevm_disk_file_entry(disk) }
|
473
|
+
# Then add the files associtaed with inactive snapshots.
|
474
|
+
miqvm.rhevmVm.snapshots.each do |snap|
|
475
|
+
snap.disks.each { |disk| @files << rhevm_disk_file_entry(disk) unless snap[:type] == 'active' }
|
476
|
+
end
|
477
|
+
end
|
478
|
+
rescue => err
|
479
|
+
$log.error "#{log_header} #{err}\n#{err.backtrace.join("\n")}"
|
480
|
+
end
|
481
|
+
end
|
482
|
+
disk_files(miqvm)
|
483
|
+
@files
|
484
|
+
end
|
485
|
+
|
486
|
+
def rhevm_disk_file_entry(disk)
|
487
|
+
storage_domain = disk[:storage_domains].first
|
488
|
+
storage_id = storage_domain && storage_domain[:id]
|
489
|
+
disk_key = disk[:image_id].blank? ? :id : :image_id
|
490
|
+
fullPath = storage_id && File.join('/dev', storage_id, disk[disk_key])
|
491
|
+
|
492
|
+
{:path => fullPath, :name => disk[disk_key], :size => disk[:actual_size].to_i}
|
493
|
+
end
|
494
|
+
private :rhevm_disk_file_entry
|
495
|
+
|
496
|
+
def disk_files(miqvm = nil)
|
497
|
+
return @disk_files if @disk_files
|
498
|
+
@disk_files = []
|
499
|
+
if @direct_file_access
|
500
|
+
@disk_files = files(miqvm)
|
501
|
+
else
|
502
|
+
begin
|
503
|
+
vim_disks = {}
|
504
|
+
if miqvm.vimVm
|
505
|
+
miqvm.vimVm.devices.each do |d|
|
506
|
+
next if d['capacityInKB'].nil?
|
507
|
+
next if (filename = d.fetch_path('backing', 'fileName')).nil?
|
508
|
+
disk = vim_disks[filename.to_s] = {}
|
509
|
+
disk[:disk_type] = (d.fetch_path('backing', 'thinProvisioned') == 'true') ? 'thin' : 'thick'
|
510
|
+
disk[:provision_size] = d['capacityInKB'].to_i * 1024
|
511
|
+
disk[:display_name] = d.fetch_path('deviceInfo', 'label').to_s
|
512
|
+
disk[:vim_index] = d['key'].to_i
|
513
|
+
disk[:disk_mode] = d['diskMode']
|
514
|
+
end
|
515
|
+
|
516
|
+
filePattern = nil
|
517
|
+
pathOnly = false
|
518
|
+
each_datastore(miqvm) do |ds, dirs|
|
519
|
+
begin
|
520
|
+
vimDs = miqvm.vim.getVimDataStore(ds)
|
521
|
+
dirs.each do |path|
|
522
|
+
vimDs.dsVmDiskFileSearch(filePattern, path, pathOnly).each do |f|
|
523
|
+
d = {:path => f['fullPath'], :name => f['path'].to_s, :size => f['fileSize'].to_i, :mtime => Time.parse(f['modification'])}
|
524
|
+
dh = vim_disks[d[:path]]
|
525
|
+
d.merge!(dh) unless dh.nil?
|
526
|
+
@disk_files << d
|
527
|
+
end
|
528
|
+
end
|
529
|
+
ensure
|
530
|
+
vimDs.release if vimDs rescue nil
|
531
|
+
end
|
532
|
+
end
|
533
|
+
elsif miqvm.rhevmVm
|
534
|
+
miqvm.rhevmVm.disks.each do |disk|
|
535
|
+
storage_domain = disk[:storage_domains].first
|
536
|
+
storage_id = storage_domain && storage_domain[:id]
|
537
|
+
disk_key = disk[:image_id].blank? ? :id : :image_id
|
538
|
+
fullPath = storage_id && File.join('/dev', storage_id, disk[disk_key])
|
539
|
+
d = {:path => fullPath, :name => disk[:name].to_s, :size => disk[:size].to_i}
|
540
|
+
@disk_files << d
|
541
|
+
end
|
542
|
+
end
|
543
|
+
rescue Exception
|
544
|
+
$log.error "VmConfig.disk_files #{$!}\n#{$!.backtrace.join("\n")}"
|
545
|
+
end
|
546
|
+
end
|
547
|
+
@disk_files
|
548
|
+
end
|
549
|
+
|
550
|
+
def add_file_sizes(xml, miqvm)
|
551
|
+
return if miqvm.nil?
|
552
|
+
begin
|
553
|
+
node = xml.root.add_element("files")
|
554
|
+
total_size = 0
|
555
|
+
files(miqvm).each do |fh|
|
556
|
+
total_size += fh[:size]
|
557
|
+
node.add_element('file', {"name" => fh[:name], "size_on_disk" => fh[:size]})
|
558
|
+
end
|
559
|
+
# Add the total size to the "files" node
|
560
|
+
node.add_attribute("size_on_disk", total_size)
|
561
|
+
|
562
|
+
free_space = 0; disk_capacity = 0
|
563
|
+
if miqvm && @vol_mgr_loaded
|
564
|
+
# Make sure we have the volume manager loaded
|
565
|
+
vmRoot = miqvm.rootTrees[0]
|
566
|
+
if vmRoot
|
567
|
+
miqvm.wholeDisks.each { |d| disk_capacity += d.size }
|
568
|
+
rootAdded = false
|
569
|
+
vmRoot.fileSystems.each do |fsd|
|
570
|
+
$log.info "FileSystem: #{fsd.fsSpec}, Mounted on: #{fsd.mountPoint}, Type: #{fsd.fs.fsType}, Free bytes: #{fsd.fs.freeBytes}"
|
571
|
+
# The root volume can appear more than once, so only add it one time.
|
572
|
+
if fsd.mountPoint == "/"
|
573
|
+
if rootAdded == false
|
574
|
+
free_space += fsd.fs.freeBytes
|
575
|
+
rootAdded = true
|
576
|
+
end
|
577
|
+
else
|
578
|
+
free_space += fsd.fs.freeBytes
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
# Now calculate free/used percent against size on disk
|
584
|
+
if !free_space.zero? && !disk_capacity.zero?
|
585
|
+
# Calculate the percentage of free space
|
586
|
+
percent_free = free_space.to_f / disk_capacity.to_f * 100
|
587
|
+
|
588
|
+
# Populate formated text fields
|
589
|
+
node.add_attributes("pct_free_wrt_size_on_disk" => percent_free, "pct_used_wrt_size_on_disk" => (100 - percent_free))
|
590
|
+
node.add_attributes("disk_free_space" => free_space, "disk_capacity" => disk_capacity)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
node.add_attributes("disk_free_space" => free_space, "disk_capacity" => disk_capacity)
|
594
|
+
rescue
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
def load_vim_snapshots(miqvm)
|
599
|
+
if @direct_file_access == false && miqvm && miqvm.vim
|
600
|
+
# If the VM does not have snapshots we can stop here
|
601
|
+
return if miqvm.snapshots.nil?
|
602
|
+
ds, dir, name = split_filename(miqvm.vmConfigFile)
|
603
|
+
|
604
|
+
# We need to connect to the host to get the snapshot file content
|
605
|
+
hostVim = nil
|
606
|
+
if miqvm.vim.isVirtualCenter?
|
607
|
+
hostVim = connect_to_host_vim('snapshot_metadata', miqvm.vmConfigFile)
|
608
|
+
return if hostVim.nil?
|
609
|
+
vimDs = hostVim.getVimDataStore(ds)
|
610
|
+
else
|
611
|
+
vimDs = miqvm.vim.getVimDataStore(ds)
|
612
|
+
end
|
613
|
+
|
614
|
+
require "metadata/VmConfig/vmxConfig"
|
615
|
+
extend Kernel.const_get("VmxConfig")
|
616
|
+
snapshot_file = File.join(dir, File.basename(name, ".*") + ".vmsd")
|
617
|
+
Timeout.timeout(60) do
|
618
|
+
process_file(convert_vmsd(vimDs.get_file_content(snapshot_file)))
|
619
|
+
end
|
620
|
+
@cfgHash
|
621
|
+
end
|
622
|
+
rescue Timeout::Error => err
|
623
|
+
$log.warn "Timeout reached transferring snapshot metadata for config file [#{miqvm.vmConfigFile}]. Message:[#{err}]"
|
624
|
+
rescue => err
|
625
|
+
$log.warn "Unable to process snapshot metadata for config file [#{miqvm.vmConfigFile}]. Message:[#{err}]"
|
626
|
+
ensure
|
627
|
+
vimDs.release if vimDs rescue nil
|
628
|
+
hostVim.release if hostVim rescue nil
|
629
|
+
end
|
630
|
+
|
631
|
+
def each_datastore(_miqvm)
|
632
|
+
files = [@configFile]
|
633
|
+
each_disks { |_device_id, filename| files << filename }
|
634
|
+
|
635
|
+
ds = Hash.new { |h, k| h[k] = {} }
|
636
|
+
files.each do |f|
|
637
|
+
dsName, dir, _name = split_filename(f)
|
638
|
+
ds[dsName][dir] = true # unless dsName.nil?
|
639
|
+
end
|
640
|
+
|
641
|
+
ds.each_pair { |ds, h| yield(ds, h.to_a.transpose.first) }
|
642
|
+
end
|
643
|
+
|
644
|
+
def getDevicePath(name, endType)
|
645
|
+
# Initialize variables
|
646
|
+
full_pos, maj_pos, device = nil, "0", name
|
647
|
+
# If the name contains a number, use it as the id
|
648
|
+
|
649
|
+
if name.index(/\d/)
|
650
|
+
device = $`.chomp(':')
|
651
|
+
maj_pos = $&
|
652
|
+
full_pos = "#{$&}#{$'}"
|
653
|
+
end
|
654
|
+
|
655
|
+
# These devices only have 1 position number, and should be grouped under a controller
|
656
|
+
maj_pos = nil if ["ethernet", "floppy", "parallel", "serial"].include?(device)
|
657
|
+
|
658
|
+
ret = [["hardware"], ["bus", {"type" => "pci"}], ["controller", {"type" => device, "id" => maj_pos}]]
|
659
|
+
# Add a device type if the major position and full position differ, otherwise
|
660
|
+
# we are processing a controller element.
|
661
|
+
ret << ["device", {"type" => endType, "id" => full_pos}] if maj_pos != full_pos
|
662
|
+
ret
|
663
|
+
end
|
664
|
+
|
665
|
+
def getSnapShotPath(name, endType, disk)
|
666
|
+
# Initialize variables
|
667
|
+
full_pos, _maj_pos, _device, pos_idx = split_data(name)
|
668
|
+
|
669
|
+
return [["vm"], ["snapshots"]] if pos_idx.nil?
|
670
|
+
ret = [["vm"], ["snapshots"], [endType, {"id" => full_pos}]]
|
671
|
+
|
672
|
+
if disk
|
673
|
+
subDevice = split_data(disk)[2]
|
674
|
+
diskPath = getSnapShotPath(disk, subDevice, nil)
|
675
|
+
ret << diskPath.pop
|
676
|
+
end
|
677
|
+
|
678
|
+
ret
|
679
|
+
end
|
680
|
+
|
681
|
+
def add_snapshot_size(xml, _miqvm)
|
682
|
+
adjust_snapshot_aligment(xml)
|
683
|
+
|
684
|
+
# First we need to loop through the snapshots and add flat files for any
|
685
|
+
# disks that are just descriptor files
|
686
|
+
xml.find_each("//*/snapshots/snapshot/disk") do |e|
|
687
|
+
unless e.attributes['filename'].nil?
|
688
|
+
find_additional_disk_files(e.attributes['filename']) do |f|
|
689
|
+
e.parent.add_element("disk", "filename" => f[:path])
|
690
|
+
end
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
# Now loop through the filename and collect stats (date/time/size)
|
695
|
+
node = xml.find_first("//*/snapshots")
|
696
|
+
node.each_recursive do |e|
|
697
|
+
if e.attributes.include?("filename")
|
698
|
+
begin
|
699
|
+
filename = normalize_file_path(e.attributes['filename'])
|
700
|
+
next if (fstat = find_file(filename)).nil?
|
701
|
+
e.add_attribute("size_on_disk", fstat[:size])
|
702
|
+
e.add_attribute("mdate_on_disk", fstat[:mtime].getutc.iso8601(6))
|
703
|
+
rescue => err
|
704
|
+
# Ignore errors here, we will try to load almost anything.
|
705
|
+
$log.error "VmConfig.add_snapshot_size [#{err.class}]-[#{err}]\n#{err.backtrace.join("\n")}"
|
706
|
+
end
|
707
|
+
end
|
708
|
+
end unless node.nil?
|
709
|
+
end
|
710
|
+
|
711
|
+
def adjust_snapshot_aligment(xml)
|
712
|
+
sn = {}
|
713
|
+
sn_root = xml.find_first("//*/snapshots")
|
714
|
+
|
715
|
+
unless sn_root.nil?
|
716
|
+
disks_by_snap = disks_by_snapshot_and_node
|
717
|
+
xml.find_each("//*/snapshots/snapshot") { |s| sn[s.attributes[:uid]] = s }
|
718
|
+
|
719
|
+
sn_list = sn.sort { |a, b| a[1].attributes[:uid].to_s <=> b[1].attributes[:uid].to_s }
|
720
|
+
clear_snapshot_disks(sn_list)
|
721
|
+
|
722
|
+
sn_list.each do |(id, snapshot)|
|
723
|
+
parent = snapshot.attributes[:parent]
|
724
|
+
unless parent.nil? || sn[parent].nil?
|
725
|
+
disks_by_snap[id.to_s]['disks'].each do |device_id, filename|
|
726
|
+
sn[parent].add_element(:disk, :node => device_id, :filename => filename)
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
filename = normalize_file_path(snapshot.attributes[:filename])
|
731
|
+
snapshot.add_element("vmem", "filename" => filename) if find_file(filename)
|
732
|
+
end
|
733
|
+
|
734
|
+
current = sn[sn_root.attributes[:current]]
|
735
|
+
unless current.nil?
|
736
|
+
disks_by_snap[:current]['disks'].each do |device_id, filename|
|
737
|
+
current.add_element(:disk, :node => device_id, :filename => filename)
|
738
|
+
end
|
739
|
+
end
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
def clear_snapshot_disks(sn_list)
|
744
|
+
sn_list.each do |(_id, snapshot)|
|
745
|
+
delete_items = []
|
746
|
+
snapshot.each { |d| delete_items << d if d.name == 'disk' }
|
747
|
+
delete_items.each(&:remove!)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
def split_data(name)
|
752
|
+
# Initialize variables
|
753
|
+
full_pos, maj_pos, device = nil, "0", name
|
754
|
+
# If the name contains a number, use it as the id
|
755
|
+
pos_idx = name.index(/\d/)
|
756
|
+
if pos_idx
|
757
|
+
full_pos = name[pos_idx..-1]
|
758
|
+
maj_pos, device = full_pos[0..0]
|
759
|
+
device = name[0...pos_idx]
|
760
|
+
end
|
761
|
+
return full_pos, maj_pos, device, pos_idx
|
762
|
+
end
|
763
|
+
|
764
|
+
def find_with_attributes(findKey, findAttr, xmlNode)
|
765
|
+
xmlNode.each_element do |e|
|
766
|
+
if e.name == findKey
|
767
|
+
found = true
|
768
|
+
findAttr.each_pair do |k, v|
|
769
|
+
found = false if e.attributes[k] != v
|
770
|
+
end
|
771
|
+
return e if found
|
772
|
+
end
|
773
|
+
end
|
774
|
+
nil
|
775
|
+
end
|
776
|
+
|
777
|
+
def add_volumes(xml, miqvm)
|
778
|
+
return unless @vol_mgr_loaded
|
779
|
+
return if miqvm.nil?
|
780
|
+
xml.root << miqvm.volumeManager.toXml.root
|
781
|
+
end
|
782
|
+
|
783
|
+
def configuration_fixup
|
784
|
+
fixup_keys = []
|
785
|
+
@cfgHash.each_pair do |k, v|
|
786
|
+
# If the cdrom does not have a filename force the 'startconnected' to false.
|
787
|
+
# This is to handle "Client Device" settings in VC that does not maintain the startconnected value.
|
788
|
+
if k.include?('.devicetype') && v.include?('cdrom')
|
789
|
+
dskKey = k.gsub('.devicetype', '')
|
790
|
+
fixup_keys << dskKey if @cfgHash[dskKey + ".filename"].to_s.delete('"').blank?
|
791
|
+
end
|
792
|
+
end
|
793
|
+
fixup_keys.each { |k| @cfgHash["#{k}.startconnected"] = 'false' }
|
794
|
+
end
|
795
|
+
|
796
|
+
def collective_size_on_disk(device_id, files = [])
|
797
|
+
total_size = 0
|
798
|
+
disks_by_node[device_id].each do |disk_name|
|
799
|
+
file = files.detect { |f| f[:path] == disk_name }
|
800
|
+
total_size += file[:size] unless file.nil?
|
801
|
+
find_additional_disk_files(disk_name) { |f| total_size += f[:size] } if @direct_file_access
|
802
|
+
end
|
803
|
+
total_size
|
804
|
+
end
|
805
|
+
|
806
|
+
def split_filename(filename)
|
807
|
+
file = filename.dup
|
808
|
+
ds = nil
|
809
|
+
if file =~ /^\[.*\] /
|
810
|
+
ds = $&.strip[1..-2]
|
811
|
+
file = $'
|
812
|
+
end
|
813
|
+
return ds, File.dirname(file), File.basename(file)
|
814
|
+
end
|
815
|
+
|
816
|
+
def base_disk_name(filename)
|
817
|
+
ds, dir, name = split_filename(filename)
|
818
|
+
if name =~ /-\d{6}[-|\.]/
|
819
|
+
# puts "#{$`}<<#{$&}>>#{$'}"
|
820
|
+
return nil if $`.nil?
|
821
|
+
basename = $`
|
822
|
+
else
|
823
|
+
basename = File.basename(name, '.*')
|
824
|
+
basename.gsub!('-flat', '')
|
825
|
+
end
|
826
|
+
|
827
|
+
key = File.join(dir, basename)
|
828
|
+
key = "[#{ds}] " + key unless ds.nil?
|
829
|
+
key
|
830
|
+
end
|
831
|
+
|
832
|
+
def self.to_h(filename)
|
833
|
+
dataHash = {}
|
834
|
+
data = filename
|
835
|
+
data = File.read(filename) unless filename.include?("\n")
|
836
|
+
data.each_line do |l|
|
837
|
+
l.strip!
|
838
|
+
next if l[0..0] == '.' || l[0..0] == '#' || l.empty?
|
839
|
+
|
840
|
+
parent = l.split('=')[0].split('.').inject(:current_level => dataHash, :hash => nil, :key => nil) do |h, k|
|
841
|
+
a1 = h[:current_level][k.strip.to_sym] ||= {}
|
842
|
+
a1 = h[:current_level][k.strip.to_sym] = {:_default => a1} unless a1.kind_of?(Hash)
|
843
|
+
{:current_level => a1, :hash => h, :key => k.strip.to_sym}
|
844
|
+
end
|
845
|
+
uh, key = parent[:hash][:current_level], parent[:key]
|
846
|
+
kkey = key.to_s.strip.to_sym
|
847
|
+
value = eval_config(l.split('=')[1], kkey)
|
848
|
+
uh[key] = value
|
849
|
+
end
|
850
|
+
dataHash
|
851
|
+
end
|
852
|
+
|
853
|
+
def self.eval_config(value, _key)
|
854
|
+
value.strip!
|
855
|
+
value = value[1..-2] if value[0, 1] == '"' && value[-1, 1] == '"'
|
856
|
+
[true, false].each { |b| return b if value.downcase == b.to_s }
|
857
|
+
return value.to_i if value =~ /^\d/
|
858
|
+
return nil if value.blank?
|
859
|
+
value
|
860
|
+
end
|
861
|
+
|
862
|
+
def normalize_file_paths(config_file = @configFile)
|
863
|
+
@cfgHash.each_pair do |k, v|
|
864
|
+
@cfgHash[k] = normalize_file_path(v, config_file) if k.include?('.filename')
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
def normalize_file_path(filename, config_file = @configFile)
|
869
|
+
cfg_ds, cfg_dir, _cfg_name = split_filename(config_file)
|
870
|
+
ds, dir, name = split_filename(filename)
|
871
|
+
if dir.blank? || dir == '.'
|
872
|
+
name = File.join(cfg_dir, name)
|
873
|
+
name = "[#{cfg_ds}] " + name unless cfg_ds.nil?
|
874
|
+
return name
|
875
|
+
else
|
876
|
+
# Check for files that do not have a ds when the config file does
|
877
|
+
return resolve_ds_path(filename) if cfg_ds && ds.nil?
|
878
|
+
end
|
879
|
+
filename
|
880
|
+
end
|
881
|
+
|
882
|
+
def disks_by_node
|
883
|
+
result = Hash.new { |h, k| h[k] = [] }
|
884
|
+
|
885
|
+
# Keep track of the disk we process so they do not get counted twice.
|
886
|
+
# This handles independent-persistent disk that do not take part in snapshots but will
|
887
|
+
# show up in each snapshot's disk list.
|
888
|
+
processed_disks = []
|
889
|
+
|
890
|
+
normalize_file_paths
|
891
|
+
getDiskFileHash.each_pair do |disk_id, path|
|
892
|
+
unless processed_disks.include?(path)
|
893
|
+
result[disk_id] << path
|
894
|
+
processed_disks << path
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
getSnapshotDiskFileHash.each_pair do |_id, h|
|
899
|
+
h['disks'].each_pair do |disk_id, path|
|
900
|
+
unless processed_disks.include?(path)
|
901
|
+
result[disk_id] << path
|
902
|
+
processed_disks << path
|
903
|
+
end
|
904
|
+
end
|
905
|
+
end
|
906
|
+
|
907
|
+
result
|
908
|
+
end
|
909
|
+
|
910
|
+
def each_disks
|
911
|
+
# Call disks_by_node since it will remove duplicate disks
|
912
|
+
disks_by_node.each_pair { |device_id, disks| disks.each { |d| yield(device_id, d) } }
|
913
|
+
end
|
914
|
+
|
915
|
+
def disks_by_snapshot_and_node
|
916
|
+
result = Hash.new { |h, k| h[k] = {} }
|
917
|
+
getSnapshotDiskFileHash.each_pair { |id, h| result[id] = h }
|
918
|
+
|
919
|
+
result[:current] = {'disks' => {}}
|
920
|
+
current_disks = result[:current]['disks']
|
921
|
+
getDiskFileHash.each_pair do |device_id, d|
|
922
|
+
# Independent disks do not par-take in snapshots. Check the mode of the parent disk.
|
923
|
+
next if @cfgHash["#{device_id}.mode"].to_s.include?('independent')
|
924
|
+
current_disks[device_id] = d
|
925
|
+
end
|
926
|
+
|
927
|
+
result
|
928
|
+
end
|
929
|
+
|
930
|
+
def find_additional_disk_files(filename)
|
931
|
+
ds, dir, name = split_filename(normalize_file_path(filename))
|
932
|
+
dfBase, ext = File.basename(name, ".*"), File.extname(name)
|
933
|
+
%w(-flat -delta).each do |disk_type|
|
934
|
+
search_filename = file_join(dir, dfBase + disk_type + ext)
|
935
|
+
search_filename = "[#{ds}] " + search_filename unless ds.nil?
|
936
|
+
f = find_file(search_filename)
|
937
|
+
yield(f) unless f.nil?
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
# Ensures that windows paths use forward slashes to full path lookups work.
|
942
|
+
def file_join(*args)
|
943
|
+
filename = File.join(*args)
|
944
|
+
filename.tr!('\\', '/') if filename[1, 1] == ':'
|
945
|
+
filename
|
946
|
+
end
|
947
|
+
end
|