manageiq-smartstate 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +31 -0
- data/.rspec +0 -1
- data/.whitesource +3 -0
- data/Gemfile +1 -1
- data/README.md +1 -2
- data/lib/MiqVm/MiqRhevmVm.rb +1 -0
- data/lib/MiqVm/MiqVm.rb +0 -7
- data/lib/blackbox/VmBlackBox.rb +1 -0
- data/lib/db/MiqBdb/MiqBdb.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbBtree.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbHash.rb +1 -0
- data/lib/db/MiqBdb/MiqBdbPage.rb +1 -0
- data/lib/disk/DiskProbe.rb +2 -1
- data/lib/disk/modules/MiqLargeFile.rb +1 -0
- data/lib/fs/ntfs/attrib_file_name.rb +1 -0
- data/lib/fs/ntfs/attrib_standard_information.rb +1 -0
- data/lib/manageiq/smartstate/version.rb +1 -1
- data/lib/metadata/MIQExtract/MIQExtract.rb +1 -0
- data/lib/metadata/ScanProfile/ScanProfilesBase.rb +1 -0
- data/lib/metadata/VmConfig/GetNativeCfg.rb +1 -0
- data/lib/metadata/VmConfig/VmConfig.rb +1 -0
- data/lib/metadata/VmConfig/ovfConfig.rb +1 -0
- data/lib/metadata/VmConfig/vmcConfig.rb +1 -0
- data/lib/metadata/VmConfig/xmlConfig.rb +1 -6
- data/lib/metadata/linux/LinuxInitProcs.rb +1 -0
- data/lib/metadata/linux/LinuxOSInfo.rb +1 -0
- data/lib/metadata/linux/LinuxPackages.rb +1 -0
- data/lib/metadata/linux/LinuxSystemd.rb +1 -0
- data/lib/metadata/linux/LinuxUsers.rb +1 -0
- data/lib/metadata/linux/MiqConaryPackages.rb +1 -0
- data/lib/metadata/linux/MiqRpmPackages.rb +1 -0
- data/lib/metadata/util/md5deep.rb +1 -0
- data/lib/metadata/util/win32/Win32Accounts.rb +1 -0
- data/lib/metadata/util/win32/Win32EventLog.rb +1 -0
- data/lib/metadata/util/win32/Win32Services.rb +1 -0
- data/lib/metadata/util/win32/Win32Software.rb +1 -0
- data/lib/metadata/util/win32/Win32System.rb +1 -0
- data/lib/metadata/util/win32/fleece_hives.rb +1 -0
- data/lib/metadata/util/win32/ms-registry.rb +1 -0
- data/lib/metadata/util/win32/remote-registry.rb +1 -0
- data/manageiq-smartstate.gemspec +4 -5
- metadata +7 -32
- data/.travis.yml +0 -15
- data/lib/MiqVm/miq_scvmm_vm.rb +0 -39
- data/lib/Scvmm/miq_hyperv_disk.rb +0 -274
- data/lib/Scvmm/miq_scvmm_parse_powershell.rb +0 -75
- data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +0 -135
- data/lib/disk/modules/MSCommon.rb +0 -354
- data/lib/disk/modules/MSVSDiffDisk.rb +0 -85
- data/lib/disk/modules/MSVSDiskProbe.rb +0 -61
- data/lib/disk/modules/MSVSDynamicDisk.rb +0 -36
- data/lib/disk/modules/MSVSFixedDisk.rb +0 -39
- data/lib/disk/modules/VhdxDisk.rb +0 -629
- data/lib/disk/modules/VhdxDiskProbe.rb +0 -46
- data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +0 -41
@@ -1,274 +0,0 @@
|
|
1
|
-
# encoding: US-ASCII
|
2
|
-
|
3
|
-
require 'util/miq_winrm'
|
4
|
-
require 'util/miq-exception'
|
5
|
-
require 'Scvmm/miq_scvmm_parse_powershell'
|
6
|
-
require 'base64'
|
7
|
-
require 'securerandom'
|
8
|
-
require 'memory_buffer'
|
9
|
-
|
10
|
-
require 'rufus/lru'
|
11
|
-
|
12
|
-
class MiqHyperVDisk
|
13
|
-
MIN_SECTORS_TO_CACHE = 64
|
14
|
-
DEF_BLOCK_CACHE_SIZE = 1200
|
15
|
-
DEBUG_CACHE_STATS = false
|
16
|
-
BREAD_RETRIES = 3
|
17
|
-
OPEN_ERRORS = %w( Exception\ calling At\ line: ).freeze
|
18
|
-
|
19
|
-
attr_reader :hostname, :virtual_disk, :file_offset, :file_size, :parser, :vm_name, :temp_snapshot_name
|
20
|
-
|
21
|
-
def initialize(hyperv_host, user, pass, port = nil, network = false)
|
22
|
-
@hostname = hyperv_host
|
23
|
-
@winrm = MiqWinRM.new
|
24
|
-
port ||= 5985
|
25
|
-
@winrm.connect(:port => port, :user => user, :password => pass, :hostname => @hostname)
|
26
|
-
@parser = MiqScvmmParsePowershell.new
|
27
|
-
@block_size = 4096
|
28
|
-
@file_size = 0
|
29
|
-
@block_cache = LruHash.new(DEF_BLOCK_CACHE_SIZE)
|
30
|
-
@cache_hits = Hash.new(0)
|
31
|
-
@cache_misses = Hash.new(0)
|
32
|
-
@network = network
|
33
|
-
@total_read_execution_time = @total_copy_from_remote_time = 0
|
34
|
-
end
|
35
|
-
|
36
|
-
def open(vm_disk)
|
37
|
-
@virtual_disk = vm_disk
|
38
|
-
@file_offset = 0
|
39
|
-
|
40
|
-
unless @network
|
41
|
-
open_script = <<-OPEN_EOL
|
42
|
-
$file_stream = [System.IO.File]::Open("#{@virtual_disk}", "Open", "Read", "Read")
|
43
|
-
$file_stream.seek(0, 0)
|
44
|
-
OPEN_EOL
|
45
|
-
@winrm.run_powershell_script(open_script)
|
46
|
-
end
|
47
|
-
|
48
|
-
stat_script = <<-STAT_EOL
|
49
|
-
(Get-Item "#{@virtual_disk}").length
|
50
|
-
STAT_EOL
|
51
|
-
file_size, stderr = @parser.parse_single_powershell_value(run_correct_powershell(stat_script))
|
52
|
-
|
53
|
-
if @network && stderr.include?("RegisterTaskDefinition")
|
54
|
-
raise MiqException::MiqInvalidCredentialsError, "Unable to obtain virtual disk size for #{vm_disk}. Check Hyper-V Host Domain Credentials."
|
55
|
-
end
|
56
|
-
OPEN_ERRORS.each { |error| raise "Unable to obtain virtual disk size for #{vm_disk}" if stderr.include?(error) }
|
57
|
-
@file_size = file_size.to_i
|
58
|
-
@end_byte_addr = @file_size - 1
|
59
|
-
@size_in_blocks, rem = @file_size.divmod(@block_size)
|
60
|
-
@size_in_blocks += 1 if rem > 0
|
61
|
-
@lba_end = @size_in_blocks - 1
|
62
|
-
end
|
63
|
-
|
64
|
-
def size
|
65
|
-
@file_size
|
66
|
-
end
|
67
|
-
|
68
|
-
def close
|
69
|
-
hit_or_miss if DEBUG_CACHE_STATS
|
70
|
-
@file_offset = 0
|
71
|
-
unless @network
|
72
|
-
close_script = <<-CLOSE_EOL
|
73
|
-
$file_stream.Close()
|
74
|
-
CLOSE_EOL
|
75
|
-
run_correct_powershell(close_script)
|
76
|
-
end
|
77
|
-
@winrm.close
|
78
|
-
@winrm = nil
|
79
|
-
end
|
80
|
-
|
81
|
-
def hit_or_miss
|
82
|
-
$log.debug "\nmiq_hyperv_disk cache hits:"
|
83
|
-
@cache_hits.keys.sort.each do |block|
|
84
|
-
$log.debug "block #{block} - #{@cache_hits[block]}"
|
85
|
-
end
|
86
|
-
$log.debug "\nmiq_hyperv_disk cache misses:"
|
87
|
-
@cache_misses.keys.sort.each do |block|
|
88
|
-
$log.debug "block #{block} - #{@cache_misses[block]}"
|
89
|
-
end
|
90
|
-
$log.debug "Total time spent copying reads from remote system is #{@total_copy_from_remote_time}"
|
91
|
-
$log.debug "Total time spent transferring and decoding reads on local system is #{@total_read_execution_time - @total_copy_from_remote_time}"
|
92
|
-
$log.debug "Total time spent processing remote reads is #{@total_read_execution_time}"
|
93
|
-
end
|
94
|
-
|
95
|
-
def seek(offset, whence = IO::SEEK_SET)
|
96
|
-
$log.debug "miq_hyperv_disk.seek(#{offset})"
|
97
|
-
case whence
|
98
|
-
when IO::SEEK_CUR
|
99
|
-
@file_offset += offset
|
100
|
-
when IO::SEEK_END
|
101
|
-
@file_offset = @end_byte_addr + offset
|
102
|
-
when IO::SEEK_SET
|
103
|
-
@file_offset = offset
|
104
|
-
end
|
105
|
-
@file_offset
|
106
|
-
end
|
107
|
-
|
108
|
-
def read(size)
|
109
|
-
$log.debug "miq_hyperv_disk.read(#{size})"
|
110
|
-
return nil if @file_offset >= @file_size
|
111
|
-
size = @file_size - @file_offset if (@file_offset + size) > @file_size
|
112
|
-
|
113
|
-
start_sector, start_offset = @file_offset.divmod(@block_size)
|
114
|
-
end_sector = (@file_offset + size - 1) / @block_size
|
115
|
-
number_sectors = end_sector - start_sector + 1
|
116
|
-
|
117
|
-
@file_offset += size
|
118
|
-
bread_cached(start_sector, number_sectors)[start_offset, size]
|
119
|
-
end
|
120
|
-
|
121
|
-
def bread_cached(start_sector, number_sectors)
|
122
|
-
$log.debug "miq_hyperv_disk.bread_cached(#{start_sector}, #{number_sectors})"
|
123
|
-
@block_cache.keys.each do |block_range|
|
124
|
-
sector_offset = start_sector - block_range.first
|
125
|
-
buffer_offset = sector_offset * @block_size
|
126
|
-
if block_range.include?(start_sector) && block_range.include?(start_sector + number_sectors - 1)
|
127
|
-
length = number_sectors * @block_size
|
128
|
-
@cache_hits[start_sector] += 1
|
129
|
-
return @block_cache[block_range][buffer_offset, length]
|
130
|
-
elsif block_range.include?(start_sector)
|
131
|
-
# This range overlaps the start of our requested read, but more data is required at the end of the request
|
132
|
-
sectors_in_range = block_range.last - start_sector
|
133
|
-
length = sectors_in_range * @block_size
|
134
|
-
remaining_blocks = number_sectors - sectors_in_range
|
135
|
-
@cache_hits[start_sector] += 1
|
136
|
-
# The "+" operator is required rather than "<<" so as not to modify the @block_cache object.
|
137
|
-
return @block_cache[block_range][buffer_offset, length] + bread_cached(block_range.last + 1, remaining_blocks)
|
138
|
-
elsif block_range.include?(start_sector + number_sectors - 1)
|
139
|
-
# This range overlaps the end of our requested read, but more data is required at the start of the request
|
140
|
-
sectors_in_range = (start_sector + number_sectors) - block_range.first
|
141
|
-
length = sectors_in_range * @block_size
|
142
|
-
remaining_blocks = number_sectors - sectors_in_range
|
143
|
-
@cache_hits[start_sector] += 1
|
144
|
-
# The "<<" operator is valid and more efficient here
|
145
|
-
return bread_cached(start_sector, remaining_blocks) << @block_cache[block_range][0, length]
|
146
|
-
elsif block_range.first > start_sector && block_range.last < start_sector + number_sectors
|
147
|
-
# This range overlaps our requested read but more data is required both before and after the range
|
148
|
-
sectors_in_range = block_range.last - block_range.first + 1
|
149
|
-
sectors_pre_range = block_range.first - start_sector
|
150
|
-
sectors_post_range = number_sectors - sectors_in_range - sectors_pre_range
|
151
|
-
# Note the mixed use of operators below.
|
152
|
-
# The first "<<" operator is valid and more efficient while the second "+" operator
|
153
|
-
# is required instead so as not to modify the in-place @block_cache object.
|
154
|
-
return bread_cached(start_sector, sectors_pre_range) <<
|
155
|
-
@block_cache[block_range] +
|
156
|
-
bread_cached(block_range.last + 1, sectors_post_range)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
block_range = entry_range(start_sector, number_sectors)
|
160
|
-
@block_cache[block_range] = bread(block_range.first, block_range.last - block_range.first + 1)
|
161
|
-
@cache_misses[start_sector] += 1
|
162
|
-
|
163
|
-
sector_offset = start_sector - block_range.first
|
164
|
-
buffer_offset = sector_offset * @block_size
|
165
|
-
length = number_sectors * @block_size
|
166
|
-
|
167
|
-
@block_cache[block_range][buffer_offset, length]
|
168
|
-
end
|
169
|
-
|
170
|
-
def bread(start_sector, number_sectors)
|
171
|
-
log_header = "MIQ(#{self.class.name}.#{__method__}:"
|
172
|
-
$log.debug "#{log_header} (#{start_sector}, #{number_sectors})"
|
173
|
-
return nil if start_sector > @lba_end
|
174
|
-
number_sectors = @size_in_blocks - start_sector if (start_sector + number_sectors) > @size_in_blocks
|
175
|
-
expected_bytes = number_sectors * @block_size
|
176
|
-
read_script = if @network
|
177
|
-
|
178
|
-
<<-READ_NETWORK_EOL
|
179
|
-
$file_stream = [System.IO.File]::Open("#{@virtual_disk}", "Open", "Read", "Read")
|
180
|
-
$bufsize = #{number_sectors * @block_size}
|
181
|
-
$buffer = New-Object System.Byte[] $bufsize
|
182
|
-
$encodedbuflen = $bufsize * 4 / 3
|
183
|
-
if (($encodedbuflen % 4) -ne 0)
|
184
|
-
{
|
185
|
-
$encodedbuflen += 4 - ($encodedbuflen % 4)
|
186
|
-
}
|
187
|
-
$encodedarray = New-Object Char[] $encodedbuflen
|
188
|
-
$file_stream.seek(#{start_sector * @block_size}, 0)
|
189
|
-
$file_stream.read($buffer, 0, #{expected_bytes})
|
190
|
-
[System.Convert]::ToBase64CharArray($buffer, 0, $bufsize, $encodedarray, 0)
|
191
|
-
[string]::join("", $encodedarray)
|
192
|
-
$file_stream.Close()
|
193
|
-
READ_NETWORK_EOL
|
194
|
-
else
|
195
|
-
|
196
|
-
<<-READ_EOL
|
197
|
-
if ($bufsize -ne #{number_sectors * @block_size})
|
198
|
-
{
|
199
|
-
$bufsize = #{number_sectors * @block_size}
|
200
|
-
$buffer = New-Object System.Byte[] $bufsize
|
201
|
-
$encodedbuflen = $bufsize * 4 / 3
|
202
|
-
if (($encodedbuflen % 4) -ne 0)
|
203
|
-
{
|
204
|
-
$encodedbuflen += 4 - ($encodedbuflen % 4)
|
205
|
-
}
|
206
|
-
$encodedarray = New-Object Char[] $encodedbuflen
|
207
|
-
}
|
208
|
-
$file_stream.seek(#{start_sector * @block_size}, 0)
|
209
|
-
$file_stream.read($buffer, 0, #{expected_bytes})
|
210
|
-
[System.Convert]::ToBase64CharArray($buffer, 0, $bufsize, $encodedarray, 0)
|
211
|
-
[string]::join("", $encodedarray)
|
212
|
-
READ_EOL
|
213
|
-
end
|
214
|
-
|
215
|
-
i = 0
|
216
|
-
(0...BREAD_RETRIES).each do
|
217
|
-
t1 = Time.now.getlocal
|
218
|
-
encoded_data = @parser.output_to_attribute(run_correct_powershell(read_script))
|
219
|
-
if encoded_data.empty?
|
220
|
-
$log.debug "#{log_header} no encoded data returned on attempt #{i}"
|
221
|
-
i += 1
|
222
|
-
continue
|
223
|
-
end
|
224
|
-
t2 = Time.now.getlocal
|
225
|
-
decoded_data = Base64.decode64(encoded_data)
|
226
|
-
@total_copy_from_remote_time += t2 - t1
|
227
|
-
@total_read_execution_time += Time.now.getlocal - t1
|
228
|
-
decoded_size = decoded_data.size
|
229
|
-
return decoded_data if expected_bytes == decoded_size
|
230
|
-
$log.debug "#{log_header} expected #{expected_bytes} bytes - got #{decoded_size} on attempt #{i}"
|
231
|
-
i += 1
|
232
|
-
end
|
233
|
-
raise "#{log_header} expected #{expected_bytes} bytes - got #{decoded_size}"
|
234
|
-
end
|
235
|
-
|
236
|
-
def snap(vm_name)
|
237
|
-
@vm_name = vm_name
|
238
|
-
@temp_snapshot_name = vm_name + SecureRandom.hex
|
239
|
-
snap_script = <<-SNAP_EOL
|
240
|
-
Checkpoint-VM -Name #{@vm_name} -SnapshotName #{@temp_snapshot_name}
|
241
|
-
SNAP_EOL
|
242
|
-
@vm_name = vm_name
|
243
|
-
@temp_snapshot_name = vm_name + SecureRandom.hex
|
244
|
-
@winrm.run_powershell_script(snap_script)
|
245
|
-
end
|
246
|
-
|
247
|
-
def delete_snap
|
248
|
-
delete_snap_script = <<-DELETE_SNAP_EOL
|
249
|
-
Remove-VMSnapShot -VMName #{@vm_name} -Name #{@temp_snapshot_name}
|
250
|
-
DELETE_SNAP_EOL
|
251
|
-
@winrm.run_powershell_script(delete_snap_script)
|
252
|
-
end
|
253
|
-
|
254
|
-
private
|
255
|
-
|
256
|
-
def run_correct_powershell(script)
|
257
|
-
return @winrm.run_elevated_powershell_script(script) if @network
|
258
|
-
@winrm.run_powershell_script(script)
|
259
|
-
end
|
260
|
-
|
261
|
-
def entry_range(start_sector, number_sectors)
|
262
|
-
# Cache entries are *multiples* of MIN_SECTORS_TO_CACHE * @blocksize in length,
|
263
|
-
# aligned to MIN_SECTORS_TO_CACHE * @blocksize byte boundaries.
|
264
|
-
# real_start_block is the aligned cache block based on the start_sector, and
|
265
|
-
# real_start_sector is the disk sector for that cache block.
|
266
|
-
real_start_block = start_sector / MIN_SECTORS_TO_CACHE
|
267
|
-
real_end_block = (start_sector + number_sectors) / MIN_SECTORS_TO_CACHE
|
268
|
-
number_cache_blocks = real_end_block - real_start_block + 1
|
269
|
-
sectors_to_read = number_cache_blocks * MIN_SECTORS_TO_CACHE
|
270
|
-
real_start_sector = real_start_block * MIN_SECTORS_TO_CACHE
|
271
|
-
end_sector = real_start_sector + sectors_to_read - 1
|
272
|
-
Range.new(real_start_sector, end_sector)
|
273
|
-
end
|
274
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
class MiqScvmmParsePowershell
|
2
|
-
def output_to_attribute(winrm_output)
|
3
|
-
attribute, stderr = stdout_stderr(winrm_output)
|
4
|
-
if stderr =~ /Exception/ || stderr =~ /At line:/
|
5
|
-
raise "Error running PowerShell command.\n #{stderr}"
|
6
|
-
end
|
7
|
-
$log.debug "MiqScvmmParsePowershell: STDERR is \"#{stderr}\"" unless stderr.nil? || $log.nil?
|
8
|
-
attribute.split("\r\n").last
|
9
|
-
end
|
10
|
-
|
11
|
-
#
|
12
|
-
# This method handles one or more lines of exactly one attribute.
|
13
|
-
#
|
14
|
-
def parse_single_attribute_values(output)
|
15
|
-
parse_attribute_values(output)
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse_multiple_attribute_values(output)
|
19
|
-
parse_attribute_values(output, true)
|
20
|
-
end
|
21
|
-
|
22
|
-
#
|
23
|
-
# This method handles one or more lines of one or more attributes.
|
24
|
-
#
|
25
|
-
def parse_attribute_values(output, multiple = nil)
|
26
|
-
stdout, stderr = parse_powershell_value(output)
|
27
|
-
lines = stdout.split("\r\n")
|
28
|
-
dashes = nil
|
29
|
-
attributes = []
|
30
|
-
attribute_names = []
|
31
|
-
lines.each do |line|
|
32
|
-
next if line.nil? || line == ""
|
33
|
-
if line =~ /^-+/
|
34
|
-
dashes = true
|
35
|
-
next
|
36
|
-
end
|
37
|
-
if dashes.nil?
|
38
|
-
attribute_names = line.split(" ")
|
39
|
-
next
|
40
|
-
end
|
41
|
-
line_parts = multiple.nil? ? [line.rstrip] : line.split(" ")
|
42
|
-
raise "Incorrect number of PowerShell Output Attributes Found" if line_parts.size != attribute_names.size
|
43
|
-
i = 0
|
44
|
-
line_hash = {}
|
45
|
-
attribute_names.each do |attribute|
|
46
|
-
line_hash[attribute] = line_parts[i]
|
47
|
-
i += 1
|
48
|
-
end
|
49
|
-
attributes << line_hash
|
50
|
-
end
|
51
|
-
return attributes, stderr
|
52
|
-
end
|
53
|
-
|
54
|
-
def parse_single_powershell_value(output)
|
55
|
-
stdout, stderr = parse_powershell_value(output)
|
56
|
-
return stdout.split("\r\n").first, stderr
|
57
|
-
end
|
58
|
-
|
59
|
-
def parse_powershell_value(output)
|
60
|
-
stdout, stderr = stdout_stderr(output)
|
61
|
-
$log.debug "MiqScvmmParsePowershell: STDOUT is \"#{stdout}\"" unless stdout.nil? || $log.nil?
|
62
|
-
$log.debug "MiqScvmmParsePowershell: STDERR is \"#{stderr}\"" unless stderr.nil? || $log.nil?
|
63
|
-
return stdout, stderr
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def stdout_stderr(output)
|
69
|
-
stdout = ""
|
70
|
-
stderr = ""
|
71
|
-
stdout << output.stdout unless output.stdout.nil?
|
72
|
-
stderr << output.stderr unless output.stderr.nil?
|
73
|
-
return stdout, stderr
|
74
|
-
end
|
75
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
# encoding: US-ASCII
|
2
|
-
|
3
|
-
require 'util/miq_winrm'
|
4
|
-
require 'Scvmm/miq_scvmm_parse_powershell'
|
5
|
-
|
6
|
-
class MiqScvmmVmSSAInfo
|
7
|
-
attr_reader :vhds, :hostname, :checkpoints, :vhd_type
|
8
|
-
def initialize(provider, user, pass, port = nil)
|
9
|
-
@checkpoints = []
|
10
|
-
@vhds = []
|
11
|
-
@hostname = nil
|
12
|
-
@vhd_type = nil
|
13
|
-
@winrm = MiqWinRM.new
|
14
|
-
winrmport = port.nil? ? 5985 : port
|
15
|
-
options = {:port => winrmport, :user => user, :password => pass, :hostname => provider}
|
16
|
-
@elevated = nil
|
17
|
-
|
18
|
-
@winrm.connect(options)
|
19
|
-
@parser = MiqScvmmParsePowershell.new
|
20
|
-
end
|
21
|
-
|
22
|
-
def close
|
23
|
-
@winrm.close
|
24
|
-
end
|
25
|
-
|
26
|
-
# Note the following method returns *all* hard disks and some common attributes from the Hyper-V host
|
27
|
-
def vm_all_harddisks(vm_name, snapshot = nil, check_snapshot = TRUE)
|
28
|
-
vhds = vm_get_disks(vm_name, snapshot, check_snapshot)
|
29
|
-
properties = vm_get_properties(vm_name)
|
30
|
-
raise "Error getting VHD(s) and Attributes for #{vm_name}" if vhds.size != properties.size
|
31
|
-
raise "No Virtual Hard Disk found for VM #{vm_name}" unless vhds.any?
|
32
|
-
|
33
|
-
i = 0
|
34
|
-
new_vhds = []
|
35
|
-
$log.debug "vm_all_harddisks: #{vhds.size} vhds found:\n"
|
36
|
-
vhds.each do |vhd|
|
37
|
-
vhd.merge!(properties[i])
|
38
|
-
new_vhds << vhd
|
39
|
-
i += 1
|
40
|
-
end
|
41
|
-
new_vhds
|
42
|
-
end
|
43
|
-
|
44
|
-
def vm_get_checkpoint(vm_name, snapshot)
|
45
|
-
get_checkpoint_script = <<-GETCHECKPOINT_EOL
|
46
|
-
Get-VMSnapShot -ComputerName localhost -VMName "#{vm_name}" -Name "#{snapshot}"| \
|
47
|
-
Select-Object -ExpandProperty Name
|
48
|
-
GETCHECKPOINT_EOL
|
49
|
-
|
50
|
-
checkpoint, stderr = @parser.parse_single_powershell_value(@winrm.run_powershell_script(get_checkpoint_script))
|
51
|
-
if stderr =~ /Unable to find a snapshot/
|
52
|
-
return nil
|
53
|
-
else
|
54
|
-
raise "Error finding Snapshot for #{vm_name}: #{stderr}" unless stderr.empty?
|
55
|
-
end
|
56
|
-
checkpoint
|
57
|
-
end
|
58
|
-
|
59
|
-
def vm_create_evm_checkpoint(vm_name, snapshot = nil)
|
60
|
-
snapshot = vm_name + "__EVM_SNAPSHOT" if snapshot.nil?
|
61
|
-
raise "Checkpoint for VM #{vm_name} Already Exists" unless vm_get_checkpoint(vm_name, snapshot).nil?
|
62
|
-
|
63
|
-
checkpoint_script = <<-CHECKPOINT_EOL
|
64
|
-
Checkpoint-VM -ComputerName localhost -Name "#{vm_name}" -SnapshotName "#{snapshot}"
|
65
|
-
CHECKPOINT_EOL
|
66
|
-
|
67
|
-
_stdout, stderr = @parser.parse_single_powershell_value(@winrm.run_powershell_script(checkpoint_script))
|
68
|
-
unless stderr.empty?
|
69
|
-
@elevated = true
|
70
|
-
_stdout, stderr = @parser.parse_single_powershell_value(@winrm.run_elevated_powershell_script(checkpoint_script))
|
71
|
-
end
|
72
|
-
raise "Unable to create Snapshot for #{vm_name}: #{stderr}" unless stderr.empty?
|
73
|
-
snapshot
|
74
|
-
end
|
75
|
-
|
76
|
-
def vm_remove_evm_checkpoint(vm_name, snapshot = nil)
|
77
|
-
snapshot = vm_name + "__EVM_SNAPSHOT" if snapshot.nil?
|
78
|
-
rm_checkpt_script = <<-RM_CHECKPOINT_EOL
|
79
|
-
Remove-VMSnapshot -ComputerName localhost -VMName "#{vm_name}" -Name "#{snapshot}"
|
80
|
-
RM_CHECKPOINT_EOL
|
81
|
-
|
82
|
-
if @elevated
|
83
|
-
_stdout, stderr = @parser.parse_single_powershell_value(@winrm.run_elevated_powershell_script(rm_checkpt_script))
|
84
|
-
else
|
85
|
-
_stdout, stderr = @parser.parse_single_powershell_value(@winrm.run_powershell_script(rm_checkpt_script))
|
86
|
-
end
|
87
|
-
raise "Unable to remove Snapshot for #{vm_name}: #{stderr}" unless stderr.empty?
|
88
|
-
end
|
89
|
-
|
90
|
-
def get_drivetype(vhd_path)
|
91
|
-
return "Network" if vhd_path[0, 2] == '\\\\'
|
92
|
-
raise "Invalid Drive Letter for Hard Drive #{vhd_path}" unless vhd_path[1, 1] == ":"
|
93
|
-
drive_letter = vhd_path[0, 1]
|
94
|
-
|
95
|
-
drivetype_script = <<-DRIVETYPE_EOL
|
96
|
-
([System.IO.DriveInfo]("#{drive_letter}")).DriveType
|
97
|
-
DRIVETYPE_EOL
|
98
|
-
drive_type, stderr = @parser.parse_single_powershell_value(@winrm.run_powershell_script(drivetype_script))
|
99
|
-
raise "Unable to get drive letter for disk #{vhd_path}: #{stderr}" unless stderr.empty? || drive_type.nil?
|
100
|
-
drive_type
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def vm_get_properties(vm_name)
|
106
|
-
properties_script = <<-PROPERTIES_EOL
|
107
|
-
Get-VMHardDiskDrive -VMName "#{vm_name}" | \
|
108
|
-
Format-Table -Property ControllerType,ControllerNumber,ControllerLocation -Autosize
|
109
|
-
PROPERTIES_EOL
|
110
|
-
|
111
|
-
properties, stderr = @parser.parse_multiple_attribute_values(@winrm.run_powershell_script(properties_script))
|
112
|
-
raise "Error getting VHD(s) and Attributes for #{vm_name}: #{stderr}" unless stderr.empty?
|
113
|
-
properties
|
114
|
-
end
|
115
|
-
|
116
|
-
def vm_get_disks(vm_name, snapshot, check_snapshot)
|
117
|
-
if check_snapshot.nil?
|
118
|
-
vhd_script = <<-VHD_EOL
|
119
|
-
Get-VMHardDiskDrive -VMName "#{vm_name}" | \
|
120
|
-
Format-Table -Property Path | out-string -Width 200
|
121
|
-
VHD_EOL
|
122
|
-
else
|
123
|
-
snapshot = vm_name + "__EVM_SNAPSHOT" if snapshot.nil?
|
124
|
-
raise "Checkpoint #{snapshot} for VM #{vm_name} missing" if vm_get_checkpoint(vm_name, snapshot).nil?
|
125
|
-
vhd_script = <<-SNAP_EOL
|
126
|
-
Get-VMSnapShot -VMName "#{vm_name}" -Name "#{snapshot}" | Get-VMHardDiskDrive | \
|
127
|
-
Format-Table -Property Path | out-string -Width 200
|
128
|
-
SNAP_EOL
|
129
|
-
end
|
130
|
-
|
131
|
-
vhds, stderr = @parser.parse_single_attribute_values(@winrm.run_powershell_script(vhd_script))
|
132
|
-
raise "Unable to obtain VHD Name(s) for #{vm_name}: #{stderr}" unless stderr.empty?
|
133
|
-
vhds
|
134
|
-
end
|
135
|
-
end
|