manageiq-smartstate 0.2.10 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd6c8e7fc62f55e3496569ccfb9b7154401a3f1c
4
- data.tar.gz: aa6b6c308e48258d4ce2f4a502907d1747332980
3
+ metadata.gz: 62cf3e30f6bab25afc33edb03fe30b6849f3ae29
4
+ data.tar.gz: caec40acfd2c105763fa1144faaf3b4d4f7710f0
5
5
  SHA512:
6
- metadata.gz: e1ef8e9e1f61e45418d4fef638e4b021a0e5e80b3e6701af800f46b6f695d316cfc23ea3bc10526c623b781961d22a44fe7a8691ff76e33cb833b8d8503176da
7
- data.tar.gz: 242e3b1c155fca702a7fc3987c169299bcd240fb2012adc87f6ea778d340f257ba80eceebf37e8919235f6d48ad9bfd2011f07af5172e3ef606700e009450e4a
6
+ metadata.gz: c0a520cf41df5a29c3494630d2d35c15deb4d453ca7fef571c4195426f218eff702da0db4e4483444ccccbf712d7f89b5e02de96b6fb5bda816107f491253dd5
7
+ data.tar.gz: 2c011d60ca5e37f0b80a10cf039eec69940675409101429dec54af3373763247c6297dbd581c6e25d66a37ffd9df917e81554b23f4b473bbb97a99d0e2461bf6
@@ -519,6 +519,7 @@ module VhdxDisk
519
519
  def parent_disk(path)
520
520
  @parent_ostruct = OpenStruct.new
521
521
  @parent_ostruct.fileName = path
522
+ @parent_ostruct.scvmm = @scvmm
522
523
  @parent_ostruct.driveType = @scvmm.get_drivetype(path)
523
524
  @parent_ostruct.hyperv_connection = @hyperv_connection if @hyperv_connection
524
525
  parent = MiqDisk.getDisk(@parent_ostruct)
@@ -269,7 +269,7 @@ module Ext3
269
269
  names.shift
270
270
 
271
271
  dir = ifs_getDirR(names, miqfs)
272
- raise "Directory '#{p}' not found" if dir.nil?
272
+ $log.info("Directory '#{p}' not found") if dir.nil?
273
273
  dir
274
274
  end
275
275
 
@@ -280,7 +280,7 @@ module ReiserFS
280
280
  names.shift
281
281
 
282
282
  dir = ifs_getDirR(names, miqfs)
283
- raise "Directory '#{p}' not found" if dir.nil?
283
+ $log.info("Directory '#{p}' not found") if dir.nil?
284
284
  dir
285
285
  end
286
286
 
@@ -264,7 +264,7 @@ module XFS
264
264
  names.shift
265
265
 
266
266
  dir = ifs_getDirR(names, miqfs)
267
- raise "Directory '#{p}' not found" if dir.nil?
267
+ $log.info("Directory '#{p}' not found") if dir.nil?
268
268
  dir
269
269
  end
270
270
 
@@ -147,7 +147,7 @@ module Ext3
147
147
 
148
148
  # /////////////////////////////////////////////////////////////////////////
149
149
  # // initialize
150
- attr_reader :numGroups, :fsId, :stream, :numBlocks, :numInodes, :fsId, :volName
150
+ attr_reader :numGroups, :fsId, :stream, :numBlocks, :numInodes, :volName
151
151
  attr_reader :sectorSize, :blockSize
152
152
 
153
153
  @@track_inodes = false
@@ -169,11 +169,10 @@ module Ext3
169
169
 
170
170
  # Grab some quick facts & make sure there's nothing wrong. Tight qualification.
171
171
  raise "Ext3::Superblock.initialize: Invalid signature=[#{@sb['signature']}]" if @sb['signature'] != SUPERBLOCK_SIG
172
- state = @sb['fs_state']
173
- raise "Ext3::Superblock.initialize: Invalid file system state" if state > FSS_END
174
- if state != FSS_CLEAN
175
- $log.warn("Ext3 file system has errors") if $log && gotBit?(state, FSS_ERR)
176
- $log.warn("Ext3 orphan inodes being recovered") if $log && gotBit?(state, FSS_ORPHAN_REC)
172
+ raise "Ext3::Superblock.initialize: Invalid file system state" if @sb['fs_state'] > FSS_END
173
+ if @sb['fs_state'] != FSS_CLEAN
174
+ $log.warn("Ext3 file system has errors") if $log && gotBit?(@sb['fs_state'], FSS_ERR)
175
+ $log.warn("Ext3 orphan inodes being recovered") if $log && gotBit?(@sb['fs_state'], FSS_ORPHAN_REC)
177
176
  end
178
177
  raise "Ext3::Superblock.initialize: Invalid error handling method=[#{@sb['err_method']}]" if @sb['err_method'] > EHM_PANIC
179
178
  raise "Ext3::Superblock.initialize: Filesystem has extents (ext4)" if gotBit?(@sb['incompat_flags'], ICF_EXTENTS)
@@ -198,7 +197,6 @@ module Ext3
198
197
  @numGroups += 1 if @lastGroupBlocks > 0
199
198
  @fsId = UUIDTools::UUID.parse_raw(@sb['fs_id'])
200
199
  @volName = @sb['vol_name']
201
- @jrnlId = UUIDTools::UUID.parse_raw(@sb['jrnl_id'])
202
200
  end
203
201
 
204
202
  # ////////////////////////////////////////////////////////////////////////////
@@ -295,8 +293,6 @@ module Ext3
295
293
  if block == 0
296
294
  @block_cache[block] = MemoryBuffer.create(@blockSize)
297
295
  else
298
- group, offset = blockNumToGroupNum(block)
299
- gde = gdt[group]
300
296
  # raise "Block #{block} is not allocated" if (not gde.blockAllocBmp[offset] and not ignore_alloc)
301
297
 
302
298
  address = blockToAddress(block) # This function will read the block into our cache
@@ -308,99 +304,11 @@ module Ext3
308
304
  @block_cache[block]
309
305
  end
310
306
 
311
- def getFeatureStrings
312
- out = "Compatible Feature Flags:\n"
313
- cff = @sb['compat_flags']
314
- out << " CFF_PREALLOC_DIR_BLKS\n" if gotBit?(cff, CFF_PREALLOC_DIR_BLKS)
315
- out << " CFF_AFS_SERVER_INODE\n" if gotBit?(cff, CFF_AFS_SERVER_INODES)
316
- out << " CFF_JOURNAL\n" if gotBit?(cff, CFF_JOURNAL)
317
- out << " CFF_EXTENDED_ATTRIBS\n" if gotBit?(cff, CFF_EXTENDED_ATTRIBS)
318
- out << " CFF_BIG_PART\n" if gotBit?(cff, CFF_BIG_PART)
319
- out << " CFF_HASH_INDEX\n" if gotBit?(cff, CFF_HASH_INDEX)
320
- extra = cff - (cff & CFF_FLAGS)
321
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
322
- out << "Incompatible Feature Flags:\n"
323
- icf = @sb['incompat_flags']
324
- out << " ICF_COMPRESSION\n" if gotBit?(icf, ICF_COMPRESSION)
325
- out << " ICF_FILE_TYPE\n" if gotBit?(icf, ICF_FILE_TYPE)
326
- out << " ICF_RECOVER_FS\n" if gotBit?(icf, ICF_RECOVER_FS)
327
- out << " ICF_JOURNAL\n" if gotBit?(icf, ICF_JOURNAL)
328
- out << " ICF_META_BG\n" if gotBit?(icf, ICF_META_BG)
329
- out << " ICF_EXTENTS\n" if gotBit?(icf, ICF_EXTENTS)
330
- out << " ICF_64BIT\n" if gotBit?(icf, ICF_64BIT)
331
- out << " ICF_MMP\n" if gotBit?(icf, ICF_MMP)
332
- out << " ICF_FLEX_BG\n" if gotBit?(icf, ICF_FLEX_BG)
333
- out << " ICF_EA_INODE\n" if gotBit?(icf, ICF_EA_INODE)
334
- out << " ICF_DIRDATA\n" if gotBit?(icf, ICF_DIRDATA)
335
- extra = icf - (icf & ICF_FLAGS)
336
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
337
- out << "Read Only Feature Flags:\n"
338
- rof = @sb['ro_flags']
339
- out << " ROF_SPARSE\n" if gotBit?(rof, ROF_SPARSE)
340
- out << " ROF_LARGE_FILES\n" if gotBit?(rof, ROF_LARGE_FILES)
341
- out << " ROF_BTREES\n" if gotBit?(rof, ROF_BTREES)
342
- extra = rof - (rof & ROF_FLAGS)
343
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
344
- out
345
- end
346
-
347
307
  # ////////////////////////////////////////////////////////////////////////////
348
308
  # // Utility functions.
349
309
 
350
310
  def gotBit?(field, bit)
351
311
  field & bit == bit
352
312
  end
353
-
354
- # Dump object.
355
- def dump
356
- out = "\#<#{self.class}:0x#{'%08x' % object_id}>\n"
357
- out << "Number of inodes : #{@sb['num_inodes']}\n"
358
- out << "Number of blocks : #{@sb['num_blocks']}\n"
359
- out << "Reserved blocks : #{@sb['reserved_blocks']}\n"
360
- out << "Unallocated blocks : #{@sb['unallocated_blocks']}\n"
361
- out << "Unallocated inodes : #{@sb['unallocated_inodes']}\n"
362
- out << "Block group 0 : #{@sb['block_group_zero']}\n"
363
- out << "Block size : #{@sb['block_size']} (#{@blockSize} bytes)\n"
364
- out << "Fragment size : #{@sb['fragment_size']} (#{fragmentSize} bytes)\n"
365
- out << "Blocks per group : #{@sb['blocks_in_group']} (#{blocksPerGroup} blocks per group)\n"
366
- out << "Fragments per group : #{@sb['fragments_in_group']} (#{fragmentsPerGroup} fragments per group)\n"
367
- out << "Inodes per group : #{@sb['inodes_in_group']} (#{inodesPerGroup} inodes per group)\n"
368
- out << "Last mount time : #{Time.at(@sb['last_mount_time'])}\n"
369
- out << "Last write time : #{Time.at(@sb['last_write_time'])}\n"
370
- out << "Current mount count : #{@sb['mount_count']}\n"
371
- out << "Maximum mount count : #{@sb['max_mount_count']}\n"
372
- out << "Signature : #{@sb['signature']}\n"
373
- out << "File system state : #{@sb['fs_state']}\n"
374
- out << "Error hndling methd : #{@sb['err_method']}\n"
375
- out << "Minor version : #{@sb['ver_minor']}\n"
376
- out << "Last consistency check: #{Time.at(@sb['last_check_time'])}\n"
377
- out << "Forced check interval : #{@sb['forced_check_int']} sec\n"
378
- out << "Creator OS : #{@sb['creator_os']}\n"
379
- out << "Major version : #{@sb['ver_major']}\n"
380
- out << "UID can use res blocks: #{@sb['uid_res_blocks']}\n"
381
- out << "GID can use res blocks: #{@sb['gid_res_blocks']}\n"
382
- if isDynamic?
383
- out << "First non-res inode : #{@sb['first_inode']}\n"
384
- out << "Size of inode : #{@sb['inode_size']}\n"
385
- out << "Block group of this SB: #{@sb['block_group']}\n"
386
- out << "Compatible features : 0x#{'%08x' % @sb['compat_flags']}\n"
387
- out << "Incompatible features : 0x#{'%08x' % @sb['incompat_flags']}\n"
388
- out << "Read Only features : 0x#{'%08x' % @sb['ro_flags']}\n"
389
- out << "File system id : #{@fsId}\n"
390
- out << "Volume name : #{@sb['vol_name']}\n"
391
- out << "Last mount path : #{@sb['last_mnt_path']}\n"
392
- out << "Algorithm usage bitmap: 0x#{'%08x' % @sb['algo_use_bmp']}\n"
393
- out << "Blocks prealloc files : #{@sb['file_prealloc_blks']}\n"
394
- out << "Blocks prealloc dirs : #{@sb['dir_prealloc_blks']}\n"
395
- out << "Journal id : #{@jrnlId}\n"
396
- out << "Journal inode : #{@sb['jrnl_inode']}\n"
397
- out << "Journal device : #{@sb['jrnl_device']}\n"
398
- out << "Orphan inode head : #{@sb['orphan_head']}\n"
399
- end
400
- out << "Number of groups : #{numGroups}\n"
401
- out << "Free bytes : #{freeBytes}\n"
402
- out << getFeatureStrings
403
- out
404
- end
405
313
  end
406
314
  end # moule Ext3
@@ -142,14 +142,13 @@ module Ext4
142
142
 
143
143
  # /////////////////////////////////////////////////////////////////////////
144
144
  # // initialize
145
- attr_reader :numGroups, :fsId, :stream, :numBlocks, :numInodes, :fsId, :volName
146
- attr_reader :sectorSize, :blockSize, :groupDescriptorSize
145
+ attr_reader :numGroups, :fsId, :stream, :numBlocks, :numInodes, :volName
146
+ attr_reader :sectorSize, :blockSize
147
147
 
148
148
  @@track_inodes = false
149
149
 
150
150
  def initialize(stream)
151
- raise "Ext4::Superblock.initialize: Nil stream" if stream.nil?
152
- @stream = stream
151
+ raise "Ext4::Superblock.initialize: Nil stream" if (@stream = stream).nil?
153
152
 
154
153
  # Seek, read & decode the superblock structure
155
154
  @stream.seek(SUPERBLOCK_OFFSET)
@@ -157,9 +156,8 @@ module Ext4
157
156
 
158
157
  # Grab some quick facts & make sure there's nothing wrong. Tight qualification.
159
158
  raise "Ext4::Superblock.initialize: Invalid signature=[#{@sb['signature']}]" if @sb['signature'] != SUPERBLOCK_SIG
160
- state = @sb['fs_state']
161
- raise "Ext4::Superblock.initialize: Invalid file system state" if state > FSS_END
162
- if state != FSS_CLEAN
159
+ raise "Ext4::Superblock.initialize: Invalid file system state" if @sb['fs_state'] > FSS_END
160
+ if (state = @sb['fs_state']) != FSS_CLEAN
163
161
  $log.warn("Ext4 file system has errors") if $log && gotBit?(state, FSS_ERR)
164
162
  $log.warn("Ext4 orphan inodes being recovered") if $log && gotBit?(state, FSS_ORPHAN_REC)
165
163
  end
@@ -185,7 +183,6 @@ module Ext4
185
183
  @numGroups += 1 if @lastGroupBlocks > 0
186
184
  @fsId = UUIDTools::UUID.parse_raw(@sb['fs_id'])
187
185
  @volName = @sb['vol_name']
188
- @jrnlId = UUIDTools::UUID.parse_raw(@sb['jrnl_id'])
189
186
  end
190
187
 
191
188
  # ////////////////////////////////////////////////////////////////////////////
@@ -293,8 +290,6 @@ module Ext4
293
290
  if block == 0
294
291
  @block_cache[block] = MemoryBuffer.create(@blockSize)
295
292
  else
296
- group, offset = blockNumToGroupNum(block)
297
- gde = gdt[group]
298
293
  # raise "Block #{block} is not allocated" if (not gde.blockAllocBmp[offset] and not ignore_alloc)
299
294
 
300
295
  address = blockToAddress(block) # This function will read the block into our cache
@@ -306,49 +301,6 @@ module Ext4
306
301
  @block_cache[block]
307
302
  end
308
303
 
309
- def getFeatureStrings
310
- out = "Compatible Feature Flags:\n"
311
- cff = @sb['compat_flags']
312
- out << " CFF_PREALLOC_DIR_BLKS\n" if gotBit?(cff, CFF_PREALLOC_DIR_BLKS)
313
- out << " CFF_AFS_SERVER_INODE\n" if gotBit?(cff, CFF_AFS_SERVER_INODES)
314
- out << " CFF_JOURNAL\n" if gotBit?(cff, CFF_JOURNAL)
315
- out << " CFF_EXTENDED_ATTRIBS\n" if gotBit?(cff, CFF_EXTENDED_ATTRIBS)
316
- out << " CFF_BIG_PART\n" if gotBit?(cff, CFF_BIG_PART)
317
- out << " CFF_HASH_INDEX\n" if gotBit?(cff, CFF_HASH_INDEX)
318
- extra = cff - (cff & CFF_FLAGS)
319
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
320
-
321
- out << "Incompatible Feature Flags:\n"
322
- icf = @sb['incompat_flags']
323
- out << " ICF_COMPRESSION\n" if gotBit?(icf, ICF_COMPRESSION)
324
- out << " ICF_FILE_TYPE\n" if gotBit?(icf, ICF_FILE_TYPE)
325
- out << " ICF_RECOVER_FS\n" if gotBit?(icf, ICF_RECOVER_FS)
326
- out << " ICF_JOURNAL\n" if gotBit?(icf, ICF_JOURNAL)
327
- out << " ICF_META_BG\n" if gotBit?(icf, ICF_META_BG)
328
- out << " ICF_EXTENTS\n" if gotBit?(icf, ICF_EXTENTS)
329
- out << " ICF_64BIT\n" if gotBit?(icf, ICF_64BIT)
330
- out << " ICF_MMP\n" if gotBit?(icf, ICF_MMP)
331
- out << " ICF_FLEX_BG\n" if gotBit?(icf, ICF_FLEX_BG)
332
- out << " ICF_EA_INODE\n" if gotBit?(icf, ICF_EA_INODE)
333
- out << " ICF_DIRDATA\n" if gotBit?(icf, ICF_DIRDATA)
334
- extra = icf - (icf & ICF_FLAGS)
335
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
336
-
337
- out << "Read Only Feature Flags:\n"
338
- rof = @sb['ro_flags']
339
- out << " ROF_SPARSE\n" if gotBit?(rof, ROF_SPARSE)
340
- out << " ROF_LARGE_FILES\n" if gotBit?(rof, ROF_LARGE_FILES)
341
- out << " ROF_BTREES\n" if gotBit?(rof, ROF_BTREES)
342
- out << " ROF_HUGE_FILE\n" if gotBit?(rof, ROF_HUGE_FILE)
343
- out << " ROF_GDT_CSUM\n" if gotBit?(rof, ROF_GDT_CSUM)
344
- out << " ROF_DIR_NLINK\n" if gotBit?(rof, ROF_DIR_NLINK)
345
- out << " ROF_EXTRA_ISIZE\n" if gotBit?(rof, ROF_EXTRA_ISIZE)
346
- extra = rof - (rof & ROF_FLAGS)
347
- out << " Extra Flags: 0x%08X\n" % extra if extra != 0
348
-
349
- out
350
- end
351
-
352
304
  # ////////////////////////////////////////////////////////////////////////////
353
305
  # // Utility functions.
354
306
 
@@ -357,56 +309,5 @@ module Ext4
357
309
  end
358
310
 
359
311
  # Dump object.
360
- def dump
361
- out = "\#<#{self.class}:0x#{'%08x' % object_id}>\n"
362
- out << "Number of inodes : #{@sb['num_inodes']}\n"
363
- out << "Number of blocks : #{@sb['num_blocks']}\n"
364
- out << "Reserved blocks : #{@sb['reserved_blocks']}\n"
365
- out << "Unallocated blocks : #{@sb['unallocated_blocks']}\n"
366
- out << "Unallocated inodes : #{@sb['unallocated_inodes']}\n"
367
- out << "Block group 0 : #{@sb['block_group_zero']}\n"
368
- out << "Block size : #{@sb['block_size']} (#{@blockSize} bytes)\n"
369
- out << "Fragment size : #{@sb['fragment_size']} (#{fragmentSize} bytes)\n"
370
- out << "Blocks per group : #{@sb['blocks_in_group']} (#{blocksPerGroup} blocks per group)\n"
371
- out << "Fragments per group : #{@sb['fragments_in_group']} (#{fragmentsPerGroup} fragments per group)\n"
372
- out << "Inodes per group : #{@sb['inodes_in_group']} (#{inodesPerGroup} inodes per group)\n"
373
- out << "Last mount time : #{Time.at(@sb['last_mount_time'])}\n"
374
- out << "Last write time : #{Time.at(@sb['last_write_time'])}\n"
375
- out << "Current mount count : #{@sb['mount_count']}\n"
376
- out << "Maximum mount count : #{@sb['max_mount_count']}\n"
377
- out << "Signature : #{@sb['signature']}\n"
378
- out << "File system state : #{@sb['fs_state']}\n"
379
- out << "Error hndling methd : #{@sb['err_method']}\n"
380
- out << "Minor version : #{@sb['ver_minor']}\n"
381
- out << "Last consistency check: #{Time.at(@sb['last_check_time'])}\n"
382
- out << "Forced check interval : #{@sb['forced_check_int']} sec\n"
383
- out << "Creator OS : #{@sb['creator_os']}\n"
384
- out << "Major version : #{@sb['ver_major']}\n"
385
- out << "UID can use res blocks: #{@sb['uid_res_blocks']}\n"
386
- out << "GID can use res blocks: #{@sb['gid_res_blocks']}\n"
387
- out << "Group descriptor size : #{@sb['group_desc_size']}\n"
388
- if isDynamic?
389
- out << "First non-res inode : #{@sb['first_inode']}\n"
390
- out << "Size of inode : #{@sb['inode_size']}\n"
391
- out << "Block group of this SB: #{@sb['block_group']}\n"
392
- out << "Compatible features : 0x#{'%08x' % @sb['compat_flags']}\n"
393
- out << "Incompatible features : 0x#{'%08x' % @sb['incompat_flags']}\n"
394
- out << "Read Only features : 0x#{'%08x' % @sb['ro_flags']}\n"
395
- out << "File system id : #{@fsId}\n"
396
- out << "Volume name : #{@sb['vol_name']}\n"
397
- out << "Last mount path : #{@sb['last_mnt_path']}\n"
398
- out << "Algorithm usage bitmap: 0x#{'%08x' % @sb['algo_use_bmp']}\n"
399
- out << "Blocks prealloc files : #{@sb['file_prealloc_blks']}\n"
400
- out << "Blocks prealloc dirs : #{@sb['dir_prealloc_blks']}\n"
401
- out << "Journal id : #{@jrnlId}\n"
402
- out << "Journal inode : #{@sb['jrnl_inode']}\n"
403
- out << "Journal device : #{@sb['jrnl_device']}\n"
404
- out << "Orphan inode head : #{@sb['orphan_head']}\n"
405
- end
406
- out << "Number of groups : #{numGroups}\n"
407
- out << "Free bytes : #{freeBytes}\n"
408
- out << getFeatureStrings
409
- out
410
- end
411
312
  end
412
313
  end # moule Ext4
@@ -9,84 +9,165 @@ module LinuxMount
9
9
  @rootFS = MiqFS.getFS(@rootVolume)
10
10
  raise "LinuxMount: could not mount root volume" unless @rootFS
11
11
 
12
+ assign_device_letters
13
+ fs_spec_hash = build_fstab_spec
14
+ build_os_names
15
+ build_mount_point_tree(fs_spec_hash)
16
+ end
17
+
18
+ #
19
+ # Given a path to a file, return true if it's a symbolic link.
20
+ # Otherwise, return false.
21
+ #
22
+ def fileSymLink?(p)
23
+ #
24
+ # We can't just expand the links in the whole path,
25
+ # because then, the target file will no longer be a link.
26
+ # So, we expand the path to the target file, then open
27
+ # the target file through that path to obtain the link data.
28
+ #
29
+ np = normalizePath(p)
30
+ d = File.dirname(np)
31
+ f = File.basename(np)
32
+
33
+ # Expand the path to the target file.
34
+ exp_dir = expandLinks(d)
35
+
36
+ # Get the file system where the target file resides, and it's local path.
37
+ fs, lp = getFsPathBase(File.join(exp_dir, f))
38
+ fs.fileSymLink?(lp)
39
+ end
40
+
41
+ #
42
+ # Given a path to a symbolic link, return the full
43
+ # path to where the link points.
44
+ #
45
+ def getLinkPath(p)
46
+ #
47
+ # We can't just expand the links in the whole path,
48
+ # because then, the target file will no longer be a link.
49
+ # So, we expand the path to the target file, then open
50
+ # the target file through that path to obtain the link data.
51
+ #
52
+ np = normalizePath(p)
53
+ d = File.dirname(np)
54
+ f = File.basename(np)
55
+
56
+ # Expand the path to the target file.
57
+ exp_dir = expandLinks(d)
58
+
59
+ # Get the file system where the target file resides, and it's local path.
60
+ fs, lp = getFsPathBase(File.join(exp_dir, f))
61
+ # Read the link data from the file, through its file system.
62
+ sp = getSymLink(fs, lp)
63
+ # Construct and return the full path to the link target.
64
+ return(sp) if sp[0, 1] == '/'
65
+ normalizePath(File.join(exp_dir, sp))
66
+ end
67
+
68
+ private
69
+
70
+ def assign_device_letters
12
71
  #
13
72
  # Assign device letters to all ide and scsi devices,
14
73
  # even if they're not visible volumes. We need to do
15
74
  # this to assign the proper device names to visible
16
75
  # devices.
17
76
  #
18
- sdLetter = 'a'
19
- ideMap = {"ide0:0" => "a", "ide0:1" => "b", "ide1:0" => "c", "ide1:1" => "d"}
77
+ sdLetter = 'a'
78
+ ideMap = {"ide0:0" => "a", "ide0:1" => "b", "ide1:0" => "c", "ide1:1" => "d"}
20
79
  @devHash = {}
21
80
  @vmConfig.getAllDiskKeys.each do |dk|
22
81
  if dk =~ /^ide.*$/
23
82
  @devHash[dk] = "/dev/hd" + ideMap[dk]
24
- $log.debug "LinuxMount: devHash[#{dk}] = /dev/hd#{ideMap[dk]}" if $log.debug?
25
83
  elsif dk =~ /^scsi.*$/
26
84
  @devHash[dk] = "/dev/sd" + sdLetter
27
- $log.debug "LinuxMount: devHash[#{dk}] = /dev/sd#{sdLetter}" if $log.debug?
28
85
  sdLetter.succ!
29
86
  end
87
+ $log.debug("LinuxMount: devHash[#{dk}] = #{devHash[dk]}") if $log.debug
30
88
  end
89
+ end
31
90
 
91
+ def build_fstab_spec
32
92
  #
33
93
  # Build hash for fstab fs_spec look up.
34
94
  #
35
- fsSpecHash = {}
95
+ fs_spec_hash = {}
36
96
  @volumes.each do |v|
37
- $log.debug "LinuxMount: Volume = #{v.dInfo.localDev} (#{v.dInfo.hardwareId}, partition = #{v.partNum})" if $log.debug?
97
+ $log.debug("LinuxMount: Volume = #{v.dInfo.localDev} (#{v.dInfo.hardwareId}, partition = #{v.partNum})") if $log.debug
38
98
  if v == @rootVolume
39
99
  fs = @rootFS
40
- else
41
- unless (fs = MiqFS.getFS(v))
42
- $log.debug "LinuxMount: No filesystem on Volume: #{v.dInfo.localDev}, partition = #{v.partNum}" if $log.debug?
43
- next
44
- end
100
+ else
101
+ (fs = MiqFS.getFS(v)) || next
45
102
  end
46
103
  @allFileSystems << fs
47
104
 
48
- #
49
- # Specific file systems can be identified by fs UUID
50
- # or file system volume label.
51
- #
52
- unless fs.volName.empty?
53
- $log.debug "LinuxMount: adding \"LABEL=#{fs.volName}\" to fsSpecHash" if $log.debug?
54
- fsSpecHash["LABEL=#{fs.volName}"] = fs
55
- $log.debug "LinuxMount: adding \"LABEL=/#{fs.volName}\" to fsSpecHash" if $log.debug?
56
- fsSpecHash["LABEL=/#{fs.volName}"] = fs
57
- end
58
- unless fs.fsId.empty?
59
- $log.debug "LinuxMount: adding \"UUID=#{fs.fsId}\" to fsSpecHash" if $log.debug?
60
- fsSpecHash["UUID=#{fs.fsId}"] = fs
61
- end
105
+ fs_spec_hash.merge!(add_fstab_entries(fs, v))
106
+ end
107
+ fs_spec_hash
108
+ end
62
109
 
63
- #
64
- # Logical volumes can be identified by their lv specific
65
- # entries under /dev.
66
- #
67
- if v.dInfo.lvObj
68
- lvName = v.dInfo.lvObj.lvName
69
- vgName = v.dInfo.lvObj.vgObj.vgName
70
- fsSpecHash["/dev/#{vgName}/#{lvName}"] = fs
71
- fsSpecHash["/dev/mapper/#{vgName.gsub('-','--')}-#{lvName.gsub('-','--')}"] = fs
72
- fsSpecHash["UUID=#{v.dInfo.lvObj.lvId}"] = fs
73
- $log.debug "LinuxMount: Volume = #{v.dInfo.localDev}, partition = #{v.partNum} is a logical volume" if $log.debug?
74
- next
75
- end
110
+ def add_fstab_entries(fs, v)
111
+ fs_spec_hash = add_fstab_fs_entries(fs)
76
112
 
77
- #
78
- # Physical volumes are identified by entries under
79
- # /dev based on OS hardware scan.
80
- # TODO: support physical volume UUIDs
81
- #
82
- $log.debug "LinuxMount: v.dInfo.hardwareId = #{v.dInfo.hardwareId}" if $log.debug?
83
- if v.partNum == 0
84
- fsSpecHash[@devHash[v.dInfo.hardwareId]] = fs
85
- else
86
- fsSpecHash[@devHash[v.dInfo.hardwareId] + v.partNum.to_s] = fs
87
- end
113
+ if v.dInfo.lvObj
114
+ fs_spec_hash.merge!(add_fstab_logical_entries(fs, v))
115
+ else
116
+ fs_spec_hash.merge!(add_fstab_physical_entry(fs, v))
117
+ end
118
+ fs_spec_hash
119
+ end
120
+
121
+ def add_fstab_fs_entries(fs)
122
+ #
123
+ # Specific file systems can be identified by fs UUID
124
+ # or file system volume label.
125
+ #
126
+ fs_spec_fs_hash = {}
127
+ unless fs.volName.empty?
128
+ $log.debug("LinuxMount: adding \"LABEL=#{fs.volName}\" & \"LABEL=/#{fs.volName}\" to hash") if $log.debug
129
+ fs_spec_fs_hash["LABEL=#{fs.volName}"] = fs
130
+ fs_spec_fs_hash["LABEL=/#{fs.volName}"] = fs
131
+ end
132
+ unless fs.fsId.empty?
133
+ $log.debug("LinuxMount: adding \"UUID=#{fs.fsId}\" to fs_spec_hash") if $log.debug
134
+ fs_spec_fs_hash["UUID=#{fs.fsId}"] = fs
135
+ end
136
+ fs_spec_fs_hash
137
+ end
138
+
139
+ def add_fstab_logical_entries(fs, v)
140
+ #
141
+ # Logical volumes can be identified by their lv specific
142
+ # entries under /dev.
143
+ #
144
+ lv_name = v.dInfo.lvObj.lvName
145
+ vg_name = v.dInfo.lvObj.vgObj.vgName
146
+ fs_spec_logical_hash = {}
147
+ fs_spec_logical_hash["/dev/#{vg_name}/#{lv_name}"] = fs
148
+ fs_spec_logical_hash["/dev/mapper/#{vg_name.gsub('-', '--')}-#{lv_name.gsub('-', '--')}"] = fs
149
+ fs_spec_logical_hash["UUID=#{v.dInfo.lvObj.lvId}"] = fs
150
+ $log.debug("LinuxMount: Volume = #{v.dInfo.localDev}, partition = #{v.partNum} is a logical volume") if $log.debug
151
+ fs_spec_logical_hash
152
+ end
153
+
154
+ def add_fstab_physical_entry(fs, v)
155
+ #
156
+ # Physical volumes are identified by entries under
157
+ # /dev based on OS hardware scan.
158
+ # TODO: support physical volume UUIDs
159
+ #
160
+ fs_spec_physical_hash = {}
161
+ $log.debug("LinuxMount: v.dInfo.hardwareId = #{v.dInfo.hardwareId}") if $log.debug
162
+ if v.partNum.zero?
163
+ fs_spec_physical_hash[@devHash[v.dInfo.hardwareId]] = fs
164
+ else
165
+ fs_spec_physical_hash[@devHash[v.dInfo.hardwareId] + v.partNum.to_s] = fs
88
166
  end
167
+ fs_spec_physical_hash
168
+ end
89
169
 
170
+ def build_os_names
90
171
  #
91
172
  # Assign OS-specific names to all physical volumes.
92
173
  #
@@ -99,79 +180,32 @@ module LinuxMount
99
180
  end
100
181
  @osNames[v.dInfo.hardwareId + ':' + v.partNum.to_s] = @devHash[v.dInfo.hardwareId] + v.partNum.to_s
101
182
  end
183
+ end
102
184
 
185
+ def build_mount_point_tree(fs_spec_hash)
103
186
  #
104
187
  # Build a tree of file systems and their associated mont points.
105
188
  #
106
189
  root_added = false
107
190
  @mountPoints = {}
108
- $log.debug "LinuxMount: processing #{FSTAB_FILE_NAME}" if $log.debug?
191
+ $log.debug("LinuxMount: processing #{FSTAB_FILE_NAME}") if $log.debug
109
192
  @rootFS.fileOpen(FSTAB_FILE_NAME, &:read).each_line do |fstl|
110
- $log.debug "LinuxMount: fstab line: #{fstl}" if $log.debug?
111
- next if fstl =~ /^#.*$/ || fstl =~ /^\s*$/
112
- fsSpec, mtPoint = fstl.split(/\s+/)
113
- $log.debug "LinuxMount: fsSpec: #{fsSpec}, mtPoint: #{mtPoint}" if $log.debug?
114
- next if fsSpec == "none" || mtPoint == "swap"
115
- next unless (fs = fsSpecHash[fsSpec])
116
- $log.debug "LinuxMount: Adding fsSpec: #{fsSpec}, mtPoint: #{mtPoint}" if $log.debug?
117
- addMountPoint(mtPoint, fs, fsSpec)
118
- root_added = true if mtPoint == '/'
193
+ $log.debug("LinuxMount: fstab line: #{fstl}") if $log.debug
194
+ root_added = true if do_fstab_line(fstl, fs_spec_hash) == '/'
119
195
  end
120
196
  saveFs(@rootFS, "/", "ROOT") unless root_added
121
- end # def fs_init
122
-
123
- #
124
- # Given a path to a file, return true if it's a symbolic link.
125
- # Otherwise, return false.
126
- #
127
- def fileSymLink?(p)
128
- #
129
- # We can't just expand the links in the whole path,
130
- # because then, the target file will no longer be a link.
131
- # So, we expand the path to the target file, then open
132
- # the target file through that path to obtain the link data.
133
- #
134
- np = normalizePath(p)
135
- d = File.dirname(np)
136
- f = File.basename(np)
137
-
138
- # Expand the path to the target file.
139
- exp_dir = expandLinks(d)
140
-
141
- # Get the file system where the target file resides, and it's local path.
142
- fs, lp = getFsPathBase(File.join(exp_dir, f))
143
- (fs.fileSymLink?(lp))
144
197
  end
145
198
 
146
- #
147
- # Given a path to a symbolic link, return the full
148
- # path to where the link points.
149
- #
150
- def getLinkPath(p)
151
- #
152
- # We can't just expand the links in the whole path,
153
- # because then, the target file will no longer be a link.
154
- # So, we expand the path to the target file, then open
155
- # the target file through that path to obtain the link data.
156
- #
157
- np = normalizePath(p)
158
- d = File.dirname(np)
159
- f = File.basename(np)
160
-
161
- # Expand the path to the target file.
162
- exp_dir = expandLinks(d)
163
-
164
- # Get the file system where the target file resides, and it's local path.
165
- fs, lp = getFsPathBase(File.join(exp_dir, f))
166
- # Read the link data from the file, through its file system.
167
- sp = getSymLink(fs, lp)
168
- # Construct and return the full path to the link target.
169
- return(sp) if sp[0, 1] == '/'
170
- (normalizePath(File.join(exp_dir, sp)))
199
+ def do_fstab_line(fstab_line, fs_spec_hash)
200
+ return if fstab_line =~ /^#.*$/ || fstab_line =~ /^\s*$/
201
+ fs_spec, mt_point = fstab_line.strip.split(/\s+/)
202
+ return if fs_spec == "none" || mt_point == "swap"
203
+ return unless (fs = fs_spec_hash[fs_spec])
204
+ $log.debug("LinuxMount: Adding fs_spec: #{fs_spec}, mt_point: #{mt_point}") if $log.debug
205
+ addMountPoint(mt_point, fs, fs_spec)
206
+ mt_point
171
207
  end
172
208
 
173
- private
174
-
175
209
  def normalizePath(p)
176
210
  # When running on windows, File.expand_path will add a drive letter.
177
211
  # Remove it if it's there.
@@ -221,7 +255,7 @@ module LinuxMount
221
255
  localPath = normalizePath(path)
222
256
  end
223
257
 
224
- p = getFsPathBase(expandLinks(localPath))
258
+ getFsPathBase(expandLinks(localPath))
225
259
  # getFsPathBase(path)
226
260
  end
227
261
 
@@ -1,5 +1,5 @@
1
1
  module ManageIQ
2
2
  module Smartstate
3
- VERSION = "0.2.10".freeze
3
+ VERSION = "0.2.11".freeze
4
4
  end
5
5
  end
@@ -55,6 +55,11 @@ module MiqLinux
55
55
  def parse_service(file)
56
56
  debug "Parsing service unit: #{file}"
57
57
 
58
+ if duplicated_link?(file)
59
+ debug("#{file} is a soft link, skip to parse.")
60
+ return nil
61
+ end
62
+
58
63
  unit = @fs.fileBasename(file)
59
64
  name = unit.gsub(".service", "")
60
65
  inif = ini(file)
@@ -92,6 +97,11 @@ module MiqLinux
92
97
  def parse_target(file)
93
98
  debug "Parsing target unit: #{file}"
94
99
 
100
+ if duplicated_link?(file)
101
+ debug("#{file} is a soft link, skip to parse.")
102
+ return nil
103
+ end
104
+
95
105
  unit = @fs.fileBasename(file)
96
106
  name = unit.gsub(".target", "")
97
107
  inif = ini(file)
@@ -119,6 +129,10 @@ module MiqLinux
119
129
  end
120
130
  end
121
131
 
132
+ def duplicated_link?(file)
133
+ existing_dirs.any? { |dir| @fs.getLinkPath(file).start_with?("#{dir}/") } if @fs.fileSymLink?(file)
134
+ end
135
+
122
136
  def debug(msg)
123
137
  $log.debug msg if $log
124
138
  end
@@ -6,12 +6,6 @@ module MiqWin32
6
6
  class Software
7
7
  attr_reader :applications, :patches, :product_keys
8
8
 
9
- PRODUCT_KEY_MAPPING = [
10
- 'DigitalProductId', :product_key,
11
- 'ProductName', :name,
12
- # 'ProductId', 'version',
13
- ]
14
-
15
9
  PRODUCTS_MAPPING = [
16
10
  'DisplayName', :name,
17
11
  'Publisher', :vendor,
@@ -58,11 +52,30 @@ module MiqWin32
58
52
  ]
59
53
 
60
54
  def initialize(_c, fs)
61
- @applications = []
62
- @patches = []
63
- @product_keys = {}
64
- @patch_install_dates = {}
55
+ @patches = @applications = []
56
+ @patch_install_dates = @product_keys = {}
57
+
58
+ reg_doc = initialize_registry_doc(fs)
59
+
60
+ registry_applications(reg_doc)
61
+ registry_patches(reg_doc)
62
+ end
63
+
64
+ # # Process application images
65
+ # e.find_each("./descendant::image") { |i| nh[:image_md5] = i.attributes['md5']; validate_image(i, nh)}
66
+ #
67
+ # def self.validate_image(imageNode, nh)
68
+ # #logger.warn("MIQ(applications-add_elements): Checking application image [#{nh.inspect}] -- [#{imageNode.to_s}]")
69
+ # x = ApplicationImage.find_by_md5(imageNode.attributes['md5'])
70
+ # if x
71
+ # #logger.warn("MIQ(applications-add_elements): Application image found [#{imageNode.attributes['md5']}]")
72
+ # else
73
+ # #logger.warn("MIQ(applications-add_elements): Application image NOT found [#{imageNode.attributes['md5']}]")
74
+ # ApplicationImage.create({:md5=>imageNode.attributes['md5'], :name=>nh['name'], :vendor=>nh['vendor'], :version=>nh['version']})
75
+ # end
76
+ # end
65
77
 
78
+ def initialize_registry_doc(fs)
66
79
  regHnd = RemoteRegistry.new(fs, true)
67
80
  # reg_doc = regHnd.loadHive("software", ["Microsoft"])
68
81
  reg_doc = regHnd.loadHive('software',
@@ -80,160 +93,144 @@ module MiqWin32
80
93
  regHnd.close
81
94
 
82
95
  @product_keys = collectProductKeys(@digital_product_keys)
96
+ reg_doc
97
+ end
83
98
 
99
+ def registry_applications(registry_doc)
84
100
  # Get the applications
85
- reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", reg_doc.root)
86
- if reg_node
87
- reg_node.each_element_with_attribute(:keyname) do |users|
88
- users.each_element_with_attribute(:keyname) do |components|
89
- if components.attributes[:keyname].downcase == "products"
90
- components.each_element_with_attribute(:keyname) do |products|
91
- attrs = XmlFind.decode(products, PRODUCTS_MAPPING)
92
- attrs.merge!(:typename => "win32_product", :product_key => @product_keys[attrs[:name]])
93
- clean_up_path(attrs)
94
- @applications << attrs
95
- end
96
- end
97
- end
98
- end
99
- end
100
-
101
+ reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", registry_doc.root)
102
+ registry_applications_user_data(reg_node) if reg_node
101
103
  ["HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths",
102
104
  "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths"].each do |reg_path|
103
- reg_node = MIQRexml.findRegElement(reg_path, reg_doc.root)
104
- if reg_node
105
- postProcessApps(reg_node, fs)
106
- reg_node.each_element_with_attribute(:keyname) do |e|
107
- attrs = XmlFind.decode(e, APP_PATHS_MAPPING)
108
- next if attrs[:name].nil?
109
- attrs.merge!(:typename => "app_path", :product_key => @product_keys[attrs[:name]])
110
- clean_up_path(attrs)
111
- @applications << attrs unless isDupApp?(attrs)
112
- end
113
- end
105
+ registry_applications_app_paths(registry_doc, reg_path)
114
106
  end
115
-
116
107
  ["HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
117
108
  "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"].each do |reg_path|
118
- reg_node = MIQRexml.findRegElement(reg_path, reg_doc.root)
119
- if reg_node
120
- reg_node.each_element_with_attribute(:keyname) do |e|
121
- attrs = XmlFind.decode(e, UNINSTALL_MAPPING)
122
- next if attrs[:name].nil?
123
- if ["security update", "update"].include?(attrs.delete(:release_type).to_s.downcase)
124
- @patch_install_dates[e.attributes[:keyname]] = Time.parse(attrs[:installed_on]) unless attrs[:installed_on].nil?
125
- next
126
- else
127
- attrs.delete(:installed_on)
128
- end
129
- attrs.merge!(:typename => "uninstall", :product_key => @product_keys[attrs[:name]])
130
- @applications << attrs unless isDupApp?(attrs)
109
+ reg_node = MIQRexml.findRegElement(reg_path, registry_doc.root)
110
+ reg_node&.each_element_with_attribute(:keyname) do |e|
111
+ registry_applications_uninstall(e)
112
+ end
113
+ end
114
+ end
115
+
116
+ def registry_applications_user_data(reg_node)
117
+ reg_node.each_element_with_attribute(:keyname) do |users|
118
+ users.each_element_with_attribute(:keyname) do |components|
119
+ next unless components.attributes[:keyname].downcase == "products"
120
+ components.each_element_with_attribute(:keyname) do |products|
121
+ add_applications(PRODUCTS_MAPPING, "win32_product", products)
131
122
  end
132
123
  end
133
124
  end
125
+ end
134
126
 
135
- # Get the patches (Win2000, Win2003, WinXP)
136
- reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix", reg_doc.root)
137
- reg_node&.each_element_with_attribute(:keyname) do |e|
138
- attrs = XmlFind.decode(e, HOTFIX_MAPPING)
127
+ def registry_applications_app_paths(registry_doc, registry_path)
128
+ return unless (reg_node = MIQRexml.findRegElement(registry_path, registry_doc.root))
129
+ postProcessApps(reg_node, fs)
130
+ reg_node.each_element_with_attribute(:keyname) do |e|
131
+ add_applications(APP_PATHS_MAPPING, "app_path", e)
132
+ end
133
+ end
139
134
 
140
- # Check both descriptions and take the first one with a value
141
- attrs.delete(:description2) if attrs[:description] || attrs[:description2].blank?
142
- attrs[:description] = attrs.delete(:description2) if attrs[:description2]
135
+ def add_applications(mapping, type_name, element)
136
+ return if (attrs = XmlFind.decode(element, mapping))[:name].nil?
137
+ attrs[:typename] = type_name; attrs[:product_key] = @product_keys[attrs[:name]]
138
+ clean_up_path(attrs)
139
+ @applications << attrs unless isDupApp?(attrs)
140
+ end
143
141
 
144
- attrs.merge!(:name => e.attributes[:keyname], :vendor => "Microsoft Corporation", :installed_on => @patch_install_dates[e.attributes[:keyname]]) unless e.attributes.nil? || e.attributes[:keyname].nil?
145
- @patches << attrs
142
+ def registry_applications_uninstall(element)
143
+ return if (attrs = XmlFind.decode(element, UNINSTALL_MAPPING))[:name].nil?
144
+ if ["security update", "update"].include?(attrs.delete(:release_type).to_s.downcase)
145
+ @patch_install_dates[e.attributes[:keyname]] = Time.parse.getlocal(attrs[:installed_on]) unless attrs[:installed_on].nil?
146
+ return
147
+ else
148
+ attrs.delete(:installed_on)
146
149
  end
150
+ attrs[:typename] = "uninstall"; attrs[:product_key] = @product_keys[attrs[:name]]
151
+ @applications << attrs unless isDupApp?(attrs)
152
+ end
147
153
 
154
+ def registry_patches(registry_doc)
155
+ # Get the patches (Win2000, Win2003, WinXP)
156
+ reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix", registry_doc.root)
157
+ reg_node&.each_element_with_attribute(:keyname) do |e|
158
+ registry_patches_hotfixes(e)
159
+ end
148
160
  # Get the patches (Vista, Win2008, Windows 7)
149
- reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\Packages", reg_doc.root)
150
- if reg_node
151
- hotfix = {}
152
- reg_node.each_element do |e|
153
- next if e.attributes.nil? || e.attributes[:keyname].nil?
154
- if e.attributes[:keyname][0, 8] == 'Package_'
155
- # Expected pattern: Package_for_KBxxx_RTM~xxxx
156
-
157
- # Get the hotfix id (KB #) out of the keyname
158
- package = e.attributes[:keyname].split("_")
159
-
160
- # If the package identifier starts with KB, use this
161
- # otherwise grab the ID from the end of the string (if it's long enough)
162
- hotfix_id = nil
163
- if (package[2][0, 2] == 'KB')
164
- hotfix_id = package[2]
165
- elsif package.size >= 4
166
- hotfix_id = package[3]
167
- else
168
- # Unknown package ID pattern, print this out
169
- str = ''
170
- e.write(str)
171
- $log.warn "Win32Software::initialize - Can't determine patch element's hotfix id: #{str}"
172
- end
173
- # don't add this package if the ID is nil
174
- next if hotfix_id.nil?
175
-
176
- hotfix_id = hotfix_id.split('~')[0]
177
-
178
- unless hotfix.key?(hotfix_id)
179
- attrs = XmlFind.decode(e, HOTFIX_MAPPING_VISTA)
180
- install_time = wtime2time(attrs[:install_time_high], attrs[:install_time_low])
181
- @patches << {:name => hotfix_id, :vendor => "Microsoft Corporation", :installed_on => install_time, :installed => 1}
182
- hotfix[hotfix_id] = true
183
- end
184
- end
185
- end
161
+ reg_node = MIQRexml.findRegElement("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\Packages", registry_doc.root)
162
+ hotfix = {}
163
+ reg_node&.each_element do |e|
164
+ registry_patches_packages(hotfix, e)
186
165
  end
187
166
  end
188
167
 
189
- # # Process application images
190
- # e.find_each("./descendant::image") { |i| nh[:image_md5] = i.attributes['md5']; validate_image(i, nh)}
191
- #
192
- # def self.validate_image(imageNode, nh)
193
- # #logger.warn("MIQ(applications-add_elements): Checking application image [#{nh.inspect}] -- [#{imageNode.to_s}]")
194
- # x = ApplicationImage.find_by_md5(imageNode.attributes['md5'])
195
- # if x
196
- # #logger.warn("MIQ(applications-add_elements): Application image found [#{imageNode.attributes['md5']}]")
197
- # else
198
- # #logger.warn("MIQ(applications-add_elements): Application image NOT found [#{imageNode.attributes['md5']}]")
199
- # ApplicationImage.create({:md5=>imageNode.attributes['md5'], :name=>nh['name'], :vendor=>nh['vendor'], :version=>nh['version']})
200
- # end
201
- # end
168
+ def registry_patches_hotfixes(element)
169
+ attrs = XmlFind.decode(element, HOTFIX_MAPPING)
170
+ # Check both descriptions and take the first one with a value
171
+ attrs.delete(:description2) if attrs[:description] || attrs[:description2].blank?
172
+ attrs[:description] = attrs.delete(:description2) if attrs[:description2]
202
173
 
203
- def to_xml(doc = nil)
204
- doc = MiqXml.createDoc(nil) unless doc
205
- applicationsToXml(doc)
206
- patchesToXml(doc)
207
- doc
174
+ attrs.merge!(:name => element.attributes[:keyname], :vendor => "Microsoft Corporation", :installed_on => @patch_install_dates[element.attributes[:keyname]]) unless element.attributes.nil? || element.attributes[:keyname].nil?
175
+ @patches << attrs
208
176
  end
209
177
 
210
- def applicationsToXml(doc = nil)
211
- doc = MiqXml.createDoc(nil) unless doc
212
- unless @applications.empty?
213
- node = doc.add_element("applications")
214
- @applications.each { |a| node.add_element("application", XmlHelpers.stringify_keys(a)) }
178
+ def registry_patches_packages(hotfix, element)
179
+ return if element.attributes.nil? || element.attributes[:keyname].nil?
180
+ if element.attributes[:keyname][0, 8] == 'Package_'
181
+ # don't add this package if the ID is nil
182
+ return if (hotfix_id = hotfix_id(e)).nil?
183
+
184
+ hotfix[hotfix_id] ||=
185
+ begin
186
+ attrs = XmlFind.decode(element, HOTFIX_MAPPING_VISTA)
187
+ install_time = wtime2time(attrs[:install_time_high], attrs[:install_time_low])
188
+ @patches << {:name => hotfix_id, :vendor => "Microsoft Corporation", :installed_on => install_time, :installed => 1}
189
+ true
190
+ end
215
191
  end
216
- doc
217
192
  end
218
193
 
219
- def patchesToXml(doc = nil)
220
- doc = MiqXml.createDoc(nil) unless doc
221
- unless @patches.empty?
222
- node = doc.add_element("patches")
223
- @patches.each { |p| node.add_element("patch", XmlHelpers.stringify_keys(p)) }
194
+ def hotfix_id(element)
195
+ # Expected pattern: Package_for_KBxxx_RTM~xxxx
196
+ # Get the hotfix id (KB #) out of the keyname
197
+ package = element.attributes[:keyname].split("_")
198
+ # If the package identifier starts with KB, use this
199
+ # otherwise grab the ID from the end of the string (if it's long enough)
200
+ if package[2][0, 2] == 'KB'
201
+ hotfix_id = package[2]
202
+ elsif package.size >= 4
203
+ hotfix_id = package[3]
204
+ else
205
+ # Unknown package ID pattern, print this out
206
+ str = ''
207
+ element.write(str)
208
+ $log.warn("Win32Software::initialize - Can't determine patch element's hotfix id: #{str}")
224
209
  end
210
+ hotfix_id.split('~')[0] unless hotfix_id.nil?
211
+ end
212
+
213
+ def to_xml(doc = nil)
214
+ doc ||= MiqXml.createDoc(nil)
215
+ element_to_xml(doc, @applications, "applications", "application")
216
+ element_to_xml(doc, @patches, "patches", "patch")
225
217
  doc
226
218
  end
227
219
 
228
- def isDupApp?(attrs)
229
- findDupApp(attrs) ? true : false
220
+ def element_to_xml(doc = nil, software_type, doc_element, node_element)
221
+ doc ||= MiqXml.createDoc(nil)
222
+ return doc if software_type.empty?
223
+ node = doc.add_element(doc_element)
224
+ software_type.each { |a| node.add_element(node_element, XmlHelpers.stringify_keys(a)) }
225
+ doc
230
226
  end
231
227
 
232
- def findDupApp(attrs)
228
+ def isDupApp?(attrs)
229
+ clean_up_path(attrs)
233
230
  @applications.each do |app|
234
- return app if app[:name] == attrs[:name]
231
+ return true if app[:name] == attrs[:name]
235
232
  end
236
- nil
233
+ false
237
234
  end
238
235
 
239
236
  def clean_up_path(attrs)
@@ -264,7 +261,6 @@ module MiqWin32
264
261
  next if appNode.text.nil?
265
262
  # st = Time.now
266
263
 
267
- fh = nil
268
264
  fileName = appNode.text
269
265
  fileName.tr!("\\", "/")
270
266
  fileName = fileName[1..-2] if fileName[0, 1] == "\"" && fileName[-1, 1] == "\""
@@ -316,8 +312,7 @@ module MiqWin32
316
312
  def wtime2time(high_time, low_time)
317
313
  th = [high_time.to_i].pack('L').unpack('L')[0] << 32
318
314
  tl = [low_time.to_i].pack('L').unpack('L')[0]
319
- time_int = ((th + tl) - 116444736000000000) / 10000000
320
- return nil if time_int < 0
315
+ return nil if (time_int = ((th + tl) - 116444736000000000) / 10000000) < 0
321
316
  Time.at(time_int).getutc rescue nil
322
317
  end
323
318
  end # Class Software
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manageiq-smartstate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.10
4
+ version: 0.2.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Developers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-02 00:00:00.000000000 Z
11
+ date: 2018-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: azure-armrest