manageiq-smartstate 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +52 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_cc.yml +5 -0
- data/.rubocop_local.yml +8 -0
- data/lib/MiqVm/miq_azure_vm.rb +43 -20
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +60 -6
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +4 -0
- data/lib/disk/modules/AzureBlobDisk.rb +6 -64
- data/lib/disk/modules/AzureDiskCommon.rb +99 -0
- data/lib/disk/modules/AzureManagedDisk.rb +55 -0
- data/lib/disk/modules/MiqLargeFile.rb +4 -15
- data/lib/manageiq/smartstate/version.rb +1 -1
- data/lib/metadata/VmConfig/VmConfig.rb +9 -3
- data/lib/metadata/util/win32/Win32EventLog.rb +1 -2
- data/manageiq-smartstate.gemspec +3 -0
- metadata +51 -4
- data/lib/disk/modules/MiqLargeFileWin32.rb +0 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 440961abf4d2b73adb7b0f459afa62e1d367eb82
|
4
|
+
data.tar.gz: e41b5ed2da90f269b303fcb1a5b56df012f32088
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a457a91e0cda2e54b9b352512062999f12fd0a049cb055692e608520820fbe22e3189b91299edefcabf5d95bccc623662ce946fd333e1dc68659b4b5f1340497
|
7
|
+
data.tar.gz: 8187dbd78395beab1cb7ba6533cb7cbf36d9abc7391cd4333e8a2956bf31b394f7b87b022d2647dd8e9b2a66c121438247cf9b937115536eb2ee1234e2477acb
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
exclude_paths:
|
3
|
+
- ".git/"
|
4
|
+
- "**.xml"
|
5
|
+
- "**.yaml"
|
6
|
+
- "**.yml"
|
7
|
+
- "lib/metadata/linux/test/Packages"
|
8
|
+
- "lib/metadata/linux/test/tc_LinuxUtils.rb"
|
9
|
+
- "locale/"
|
10
|
+
- "spec/"
|
11
|
+
- "test/"
|
12
|
+
- "tools/"
|
13
|
+
- "tmp/"
|
14
|
+
engines:
|
15
|
+
brakeman:
|
16
|
+
# very slow :sad_panda:
|
17
|
+
enabled: false
|
18
|
+
bundler-audit:
|
19
|
+
# requires Gemfile.lock
|
20
|
+
enabled: false
|
21
|
+
csslint:
|
22
|
+
enabled: false
|
23
|
+
duplication:
|
24
|
+
enabled: true
|
25
|
+
config:
|
26
|
+
languages:
|
27
|
+
ruby:
|
28
|
+
mass_threshold: 25
|
29
|
+
javascript:
|
30
|
+
eslint:
|
31
|
+
enabled: false
|
32
|
+
channel: "eslint-3"
|
33
|
+
fixme:
|
34
|
+
# let's enable later
|
35
|
+
enabled: false
|
36
|
+
markdownlint:
|
37
|
+
# let's enable later
|
38
|
+
enabled: false
|
39
|
+
rubocop:
|
40
|
+
enabled: true
|
41
|
+
config: '.rubocop_cc.yml'
|
42
|
+
prepare:
|
43
|
+
fetch:
|
44
|
+
- url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml"
|
45
|
+
path: ".rubocop_base.yml"
|
46
|
+
- url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_cc_base.yml"
|
47
|
+
path: ".rubocop_cc_base.yml"
|
48
|
+
ratings:
|
49
|
+
paths:
|
50
|
+
- Gemfile.lock
|
51
|
+
- "**.rake"
|
52
|
+
- "**.rb"
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.rubocop_cc.yml
ADDED
data/.rubocop_local.yml
ADDED
data/lib/MiqVm/miq_azure_vm.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'MiqVm/MiqVm'
|
2
2
|
require 'disk/modules/AzureBlobDisk'
|
3
|
+
require 'disk/modules/AzureManagedDisk'
|
3
4
|
require 'disk/modules/miq_disk_cache'
|
4
5
|
|
5
6
|
class MiqAzureVm < MiqVm
|
6
7
|
def initialize(azure_handle, args)
|
7
|
-
@azure_handle
|
8
|
-
@uri
|
8
|
+
@azure_handle = azure_handle
|
9
|
+
@uri = nil
|
10
|
+
@snap_name = nil
|
11
|
+
@resource_group = args[:resource_group]
|
9
12
|
|
10
13
|
raise ArgumentError, "MiqAzureVm: missing required arg :name" unless (@name = args[:name])
|
11
14
|
|
@@ -13,7 +16,18 @@ class MiqAzureVm < MiqVm
|
|
13
16
|
@uri = args[:image_uri]
|
14
17
|
elsif args[:resource_group] && args[:name]
|
15
18
|
vm_obj = vm_svc.get(@name, args[:resource_group])
|
16
|
-
|
19
|
+
os_disk = vm_obj.properties.storage_profile.os_disk
|
20
|
+
if vm_obj.managed_disk?
|
21
|
+
#
|
22
|
+
# Use the EVM SNAPSHOT Added by the Provider
|
23
|
+
#
|
24
|
+
@snap_name = os_disk.name + "__EVM__SSA__SNAPSHOT"
|
25
|
+
else
|
26
|
+
#
|
27
|
+
# Non-Managed Disk Snapshot handling will be added here by a separate PR.
|
28
|
+
#
|
29
|
+
@uri = os_disk.vhd.uri
|
30
|
+
end
|
17
31
|
else
|
18
32
|
raise ArgumentError, "MiqAzureVm: missing required args: :image_uri or :resource_group"
|
19
33
|
end
|
@@ -24,13 +38,14 @@ class MiqAzureVm < MiqVm
|
|
24
38
|
def getCfg
|
25
39
|
cfg_hash = {}
|
26
40
|
cfg_hash['displayname'] = @name
|
41
|
+
file_name = @uri ? @uri : @snap_name
|
27
42
|
|
28
|
-
$log.debug
|
43
|
+
$log.debug("MiqAzureVm#getCfg: disk = #{file_name}")
|
29
44
|
|
30
45
|
tag = "scsi0:0"
|
31
46
|
cfg_hash["#{tag}.present"] = "true"
|
32
47
|
cfg_hash["#{tag}.devicetype"] = "disk"
|
33
|
-
cfg_hash["#{tag}.filename"] =
|
48
|
+
cfg_hash["#{tag}.filename"] = file_name
|
34
49
|
|
35
50
|
cfg_hash
|
36
51
|
end
|
@@ -38,30 +53,23 @@ class MiqAzureVm < MiqVm
|
|
38
53
|
def openDisks(diskFiles)
|
39
54
|
p_volumes = []
|
40
55
|
|
41
|
-
$log.debug
|
56
|
+
$log.debug("openDisks: #{diskFiles.size} disk files supplied.")
|
42
57
|
|
43
58
|
#
|
44
59
|
# Build a list of the VM's physical volumes.
|
45
60
|
#
|
46
61
|
diskFiles.each do |dtag, df|
|
47
62
|
$log.debug "openDisks: processing disk file (#{dtag}): #{df}"
|
48
|
-
|
49
|
-
|
50
|
-
dInfo.fileName = df
|
51
|
-
dInfo.hardwareId = dtag
|
52
|
-
disk_format = @vmConfig.getHash["#{dtag}.format"]
|
53
|
-
dInfo.format = disk_format unless disk_format.blank?
|
54
|
-
|
55
|
-
mode = @vmConfig.getHash["#{dtag}.mode"]
|
56
|
-
|
57
|
-
dInfo.hardwareId = dtag
|
58
|
-
dInfo.rawDisk = true
|
63
|
+
d_info = open_disks_info(dtag, df)
|
59
64
|
|
60
65
|
begin
|
61
|
-
|
66
|
+
if @uri
|
67
|
+
d = MiqDiskCache.new(AzureBlobDisk.new(sa_svc, @uri, d_info), 100, 128)
|
68
|
+
else
|
69
|
+
d = MiqDiskCache.new(AzureManagedDisk.new(snap_svc, @snap_name, d_info), 100, 128)
|
70
|
+
end
|
62
71
|
rescue => err
|
63
|
-
$log.error
|
64
|
-
$log.error err.to_s
|
72
|
+
$log.error("#{err}: Couldn't open disk file: #{df}")
|
65
73
|
$log.debug err.backtrace.join("\n")
|
66
74
|
@diskInitErrors[df] = err.to_s
|
67
75
|
next
|
@@ -86,6 +94,17 @@ class MiqAzureVm < MiqVm
|
|
86
94
|
p_volumes
|
87
95
|
end # def openDisks
|
88
96
|
|
97
|
+
def open_disks_info(disk_tag, disk_file)
|
98
|
+
disk_info = OpenStruct.new
|
99
|
+
disk_info.fileName = disk_file
|
100
|
+
disk_info.hardwareId = disk_tag
|
101
|
+
disk_format = @vmConfig.getHash["#{disk_tag}.format"]
|
102
|
+
disk_info.format = disk_format unless disk_format.blank?
|
103
|
+
disk_info.rawDisk = true
|
104
|
+
disk_info.resource_group = @resource_group
|
105
|
+
disk_info
|
106
|
+
end
|
107
|
+
|
89
108
|
def vm_svc
|
90
109
|
@vm_svc ||= Azure::Armrest::VirtualMachineService.new(@azure_handle)
|
91
110
|
end
|
@@ -93,4 +112,8 @@ class MiqAzureVm < MiqVm
|
|
93
112
|
def sa_svc
|
94
113
|
@sa_svc ||= Azure::Armrest::StorageAccountService.new(@azure_handle)
|
95
114
|
end
|
115
|
+
|
116
|
+
def snap_svc
|
117
|
+
@snap_svc ||= Azure::Armrest::Storage::SnapshotService.new(@azure_handle)
|
118
|
+
end
|
96
119
|
end
|
@@ -11,20 +11,23 @@ module MiqOpenStackCommon
|
|
11
11
|
send("disk_format_glance_#{image_service.version}", snapshot_image_id)
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
14
|
+
def get_image_metadata_snapshot_id(image)
|
15
|
+
image.metadata.each do |m|
|
16
|
+
next if m.key != "block_device_mapping"
|
17
|
+
return m.value[0]['snapshot_id']
|
18
|
+
end
|
19
|
+
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
$log.debug "#{log_prefix}: image = #{image.class.name}"
|
21
|
+
def download_image_data_glance_v2(image)
|
22
|
+
log_prefix = "#{self.class.name}##{__method__}"
|
20
23
|
|
24
|
+
image_id = image.id
|
21
25
|
iname = image.name
|
22
26
|
isize = image.size.to_i
|
23
27
|
$log.debug "#{log_prefix}: iname = #{iname}"
|
24
28
|
$log.debug "#{log_prefix}: isize = #{isize}"
|
25
29
|
|
26
30
|
raise "Image: #{iname} (#{image_id}) is empty" unless isize > 0
|
27
|
-
|
28
31
|
tot = 0
|
29
32
|
tf = MiqTempfile.new(iname, :encoding => 'ascii-8bit')
|
30
33
|
$log.debug "#{log_prefix}: saving image to #{tf.path}"
|
@@ -50,6 +53,57 @@ module MiqOpenStackCommon
|
|
50
53
|
end
|
51
54
|
tf
|
52
55
|
end
|
56
|
+
|
57
|
+
def create_image_from_snapshot(snapshot_id, disk_format)
|
58
|
+
snapshot = volume_service.snapshots.get(snapshot_id)
|
59
|
+
volume_options = {
|
60
|
+
:name => "Temp Volume from #{snapshot.name}",
|
61
|
+
:size => snapshot.size,
|
62
|
+
:snapshot_id => snapshot_id
|
63
|
+
}
|
64
|
+
volume = volume_service.volumes.new(volume_options)
|
65
|
+
volume.save
|
66
|
+
begin
|
67
|
+
while volume.status != 'available'
|
68
|
+
sleep(10)
|
69
|
+
volume = volume_service.volumes.get(volume.id)
|
70
|
+
end
|
71
|
+
response = volume_service.action(volume.id, 'os-volume_upload_image' => {
|
72
|
+
:image_name => "Temp Image from #{snapshot.name}",
|
73
|
+
:disk_format => disk_format})
|
74
|
+
image_id = response.body["os-volume_upload_image"]["image_id"]
|
75
|
+
while image_service.images.get(image_id).status.downcase != 'active'
|
76
|
+
sleep(10)
|
77
|
+
end
|
78
|
+
return image_service.images.get(image_id)
|
79
|
+
ensure
|
80
|
+
volume.destroy
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_image_file_glance_v2(image_id)
|
85
|
+
log_prefix = "#{self.class.name}##{__method__}"
|
86
|
+
|
87
|
+
image = image_service.images.get(image_id)
|
88
|
+
raise "Image #{image_id} not found" unless image
|
89
|
+
$log.debug "#{log_prefix}: image = #{image.class.name}"
|
90
|
+
|
91
|
+
if image.size.to_i == 0
|
92
|
+
# try getting image from metadata; oddly the image metadata is only available if
|
93
|
+
# image is queried through compute service
|
94
|
+
unless (snapshot_id = get_image_metadata_snapshot_id(compute_service.images.get(image_id))).nil?
|
95
|
+
temp_image = create_image_from_snapshot(snapshot_id, image.disk_format)
|
96
|
+
begin
|
97
|
+
tf = download_image_data_glance_v2(temp_image)
|
98
|
+
ensure
|
99
|
+
temp_image.destroy
|
100
|
+
end
|
101
|
+
end
|
102
|
+
else
|
103
|
+
tf = download_image_data_glance_v2(image)
|
104
|
+
end
|
105
|
+
tf
|
106
|
+
end
|
53
107
|
|
54
108
|
def get_image_file_glance_v1(image_id)
|
55
109
|
log_prefix = "#{self.class.name}##{__method__}"
|
@@ -28,6 +28,10 @@ class MiqOpenStackInstance
|
|
28
28
|
@image_service ||= @openstack_handle.detect_image_service
|
29
29
|
end
|
30
30
|
|
31
|
+
def volume_service
|
32
|
+
@volume_service ||= @openstack_handle.detect_volume_service
|
33
|
+
end
|
34
|
+
|
31
35
|
def instance
|
32
36
|
@instance ||= compute_service.servers.get(@instance_id)
|
33
37
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require "disk/modules/AzureDiskCommon"
|
1
2
|
require_relative "../MiqDisk"
|
2
3
|
require 'ostruct'
|
3
4
|
|
4
5
|
module AzureBlobDisk
|
6
|
+
include AzureDiskCommon
|
5
7
|
# The maximum read length that supports MD5 return.
|
6
8
|
MAX_READ_LEN = 1024 * 1024 * 4
|
7
9
|
|
@@ -16,50 +18,19 @@ module AzureBlobDisk
|
|
16
18
|
|
17
19
|
def d_init
|
18
20
|
@diskType = "azure-blob"
|
19
|
-
@blockSize =
|
21
|
+
@blockSize = AzureDiskCommon::SECTOR_LENGTH
|
20
22
|
@blob_uri = @dInfo.blob_uri
|
21
23
|
@storage_acct_svc = @dInfo.storage_acct_svc
|
22
|
-
|
23
|
-
uri_info = @storage_acct_svc.parse_uri(@blob_uri)
|
24
|
-
@container = uri_info[:container]
|
25
|
-
@blob = uri_info[:blob]
|
26
|
-
@acct_name = uri_info[:account_name]
|
27
|
-
@snapshot = uri_info[:snapshot]
|
28
|
-
|
29
|
-
@storage_acct = @storage_acct_svc.accounts_by_name[@acct_name]
|
30
|
-
raise "AzureBlob: Storage account #{@acct_name} not found." unless @storage_acct
|
31
|
-
|
32
|
-
$log.debug "AzureBlobDisk: open(#{@blob_uri})"
|
33
|
-
@t0 = Time.now.to_i
|
34
|
-
@reads = 0
|
35
|
-
@bytes = 0
|
36
|
-
@split_reads = 0
|
24
|
+
d_init_common(@dInfo)
|
37
25
|
end
|
38
26
|
|
39
27
|
def d_close
|
40
|
-
|
41
|
-
t1 = Time.now.to_i
|
42
|
-
$log.debug "AzureBlobDisk: close(#{@blob_uri})"
|
43
|
-
$log.debug "AzureBlobDisk: (#{@blob_uri}) time: #{t1 - @t0}"
|
44
|
-
$log.debug "AzureBlobDisk: (#{@blob_uri}) reads: #{@reads}, split_reads: #{@split_reads}"
|
45
|
-
$log.debug "AzureBlobDisk: (#{@blob_uri}) bytes: #{@bytes}"
|
46
|
-
nil
|
28
|
+
d_close_common
|
47
29
|
end
|
48
30
|
|
49
31
|
def d_read(pos, len)
|
50
32
|
$log.debug "AzureBlobDisk#d_read(#{pos}, #{len})"
|
51
|
-
|
52
|
-
|
53
|
-
@split_reads += 1
|
54
|
-
ret = ""
|
55
|
-
blocks, rem = len.divmod(MAX_READ_LEN)
|
56
|
-
|
57
|
-
blocks.times do
|
58
|
-
ret << blob_read(pos, MAX_READ_LEN)
|
59
|
-
end
|
60
|
-
ret << blob_read(pos, rem) if rem > 0
|
61
|
-
|
62
|
-
ret
|
33
|
+
d_read_common(pos, len)
|
63
34
|
end
|
64
35
|
|
65
36
|
def d_size
|
@@ -69,33 +40,4 @@ module AzureBlobDisk
|
|
69
40
|
def d_write(_pos, _buf, _len)
|
70
41
|
raise "Write operation not supported."
|
71
42
|
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def blob_read(start_byte, length)
|
76
|
-
$log.debug "AzureBlobDisk#blob_read(#{start_byte}, #{length})"
|
77
|
-
options = {
|
78
|
-
:start_byte => start_byte,
|
79
|
-
:length => length
|
80
|
-
}
|
81
|
-
options[:date] = @snapshot if @snapshot
|
82
|
-
|
83
|
-
ret = @storage_acct.get_blob_raw(@container, @blob, key, options)
|
84
|
-
|
85
|
-
@reads += 1
|
86
|
-
@bytes += ret.body.length
|
87
|
-
|
88
|
-
ret.body
|
89
|
-
end
|
90
|
-
|
91
|
-
def blob_properties
|
92
|
-
@blob_properties ||= begin
|
93
|
-
options = @snapshot ? {:date => @snapshot} : {}
|
94
|
-
@storage_acct.blob_properties(@container, @blob, key, options)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def key
|
99
|
-
@key ||= @storage_acct_svc.list_account_keys(@storage_acct.name, @storage_acct.resource_group).fetch('key1')
|
100
|
-
end
|
101
43
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative '../MiqDisk'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module AzureDiskCommon
|
5
|
+
# The maximum read length that supports MD5 return.
|
6
|
+
MAX_READ_LEN = 1024 * 1024 * 4
|
7
|
+
SECTOR_LENGTH = 512
|
8
|
+
|
9
|
+
def d_init_common(d_info)
|
10
|
+
@blockSize = SECTOR_LENGTH
|
11
|
+
if d_info.blob_uri
|
12
|
+
d_init_blob_disk(d_info)
|
13
|
+
else
|
14
|
+
d_init_managed_disk(d_info)
|
15
|
+
end
|
16
|
+
$log.debug("#{@class}: open(#{@disk_path})")
|
17
|
+
@t0 = Time.now.to_i
|
18
|
+
@reads = 0
|
19
|
+
@bytes = 0
|
20
|
+
@split_reads = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def d_init_blob_disk(d_info)
|
24
|
+
@blob_uri = d_info.blob_uri
|
25
|
+
@storage_acct_svc = d_info.storage_acct_svc
|
26
|
+
@my_class = "AzureBlobDisk"
|
27
|
+
uri_info = @storage_acct_svc.parse_uri(@blob_uri)
|
28
|
+
@container = uri_info[:container]
|
29
|
+
@blob = uri_info[:blob]
|
30
|
+
@acct_name = uri_info[:account_name]
|
31
|
+
@snapshot = uri_info[:snapshot]
|
32
|
+
@storage_acct = @storage_acct_svc.accounts_by_name[@acct_name]
|
33
|
+
@disk_path = @blob_uri
|
34
|
+
raise "AzureBlob: Storage account #{@acct_name} not found." unless @storage_acct
|
35
|
+
end
|
36
|
+
|
37
|
+
def d_init_managed_disk(d_info)
|
38
|
+
@disk_name = d_info.disk_name
|
39
|
+
@storage_disk_svc = d_info.storage_disk_svc
|
40
|
+
@resource_group = d_info.resource_group
|
41
|
+
@my_class = "AzureManagedDisk"
|
42
|
+
@disk_path = @disk_name
|
43
|
+
end
|
44
|
+
|
45
|
+
def d_close_common
|
46
|
+
return nil unless $log.debug?
|
47
|
+
t1 = Time.now.to_i
|
48
|
+
$log.debug("#{@my_class}: close(#{@disk_path})")
|
49
|
+
$log.debug("#{@my_class}: (#{@disk_path}) time: #{t1 - @t0}")
|
50
|
+
$log.debug("#{@my_class}: (#{@disk_path}) reads: #{@reads}, split_reads: #{@split_reads}")
|
51
|
+
$log.debug("#{@my_class}: (#{@disk_path}) bytes: #{@bytes}")
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def d_read_common(pos, len)
|
56
|
+
return blob_read(pos, len) unless len > MAX_READ_LEN
|
57
|
+
|
58
|
+
@split_reads += 1
|
59
|
+
ret = ""
|
60
|
+
blocks, rem = len.divmod(MAX_READ_LEN)
|
61
|
+
|
62
|
+
blocks.times do
|
63
|
+
ret << blob_read(pos, MAX_READ_LEN)
|
64
|
+
end
|
65
|
+
ret << blob_read(pos, rem) if rem > 0
|
66
|
+
|
67
|
+
ret
|
68
|
+
end
|
69
|
+
|
70
|
+
def blob_properties
|
71
|
+
@blob_properties ||= begin
|
72
|
+
options = @snapshot ? {:date => @snapshot} : {}
|
73
|
+
@storage_acct.blob_properties(@container, @blob, key, options)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def blob_read(start_byte, length)
|
78
|
+
$log.debug("#{@my_class}#blob_read(#{start_byte}, #{length})")
|
79
|
+
options = {
|
80
|
+
:start_byte => start_byte,
|
81
|
+
:length => length
|
82
|
+
}
|
83
|
+
if @storage_acct
|
84
|
+
options[:date] = @snapshot if @snapshot
|
85
|
+
ret = @storage_acct.get_blob_raw(@container, @blob, key, options)
|
86
|
+
else
|
87
|
+
ret = @storage_disk_svc.get_blob_raw(@disk_name, @resource_group, options)
|
88
|
+
end
|
89
|
+
|
90
|
+
@reads += 1
|
91
|
+
@bytes += ret.body.length
|
92
|
+
|
93
|
+
ret.body
|
94
|
+
end
|
95
|
+
|
96
|
+
def key
|
97
|
+
@key ||= @storage_acct_svc.list_account_keys(@storage_acct.name, @storage_acct.resource_group).fetch('key1')
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "disk/modules/AzureDiskCommon"
|
2
|
+
require_relative "../MiqDisk"
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module AzureManagedDisk
|
6
|
+
include AzureDiskCommon
|
7
|
+
def self.new(svc, disk_name, dInfo = nil)
|
8
|
+
d_info = dInfo || OpenStruct.new
|
9
|
+
d_info.storage_disk_svc = svc
|
10
|
+
d_info.disk_name = disk_name
|
11
|
+
d_info.fileName = disk_name
|
12
|
+
|
13
|
+
MiqDisk.new(self, d_info, 0)
|
14
|
+
end
|
15
|
+
|
16
|
+
def d_init
|
17
|
+
@diskType = "azure-managed"
|
18
|
+
@blockSize = SECTOR_LENGTH
|
19
|
+
@disk_name = @dInfo.disk_name
|
20
|
+
@storage_disk_svc = @dInfo.storage_disk_svc
|
21
|
+
@resource_group = @dInfo.resource_group
|
22
|
+
d_init_common(@dInfo)
|
23
|
+
end
|
24
|
+
|
25
|
+
def d_close
|
26
|
+
d_close_common
|
27
|
+
end
|
28
|
+
|
29
|
+
def d_read(pos, len)
|
30
|
+
$log.debug("AzureManagedDisk#d_read(#{pos}, #{len})")
|
31
|
+
d_read_common(pos, len)
|
32
|
+
end
|
33
|
+
|
34
|
+
def d_size
|
35
|
+
@d_size ||= blob_headers[:content_range].split("/")[1].to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def d_write(_pos, _buf, _len)
|
39
|
+
raise "Write operation not supported."
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def blob_headers
|
45
|
+
$log.debug("AzureManagedDisk#blob_headers")
|
46
|
+
@blob_headers ||= begin
|
47
|
+
options = {
|
48
|
+
:start_byte => 0,
|
49
|
+
:length => 1
|
50
|
+
}
|
51
|
+
data = @storage_disk_svc.get_blob_raw(@disk_name, @resource_group, options)
|
52
|
+
data.headers
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -6,15 +6,11 @@ if Sys::Platform::IMPL == :linux
|
|
6
6
|
require 'linux_block_device'
|
7
7
|
require 'disk/modules/RawBlockIO'
|
8
8
|
end
|
9
|
-
elsif Sys::Platform::OS == :windows
|
10
|
-
require 'disk/modules/MiqLargeFileWin32'
|
11
9
|
end
|
12
10
|
|
13
11
|
module MiqLargeFile
|
14
12
|
def self.open(file_name, flags)
|
15
13
|
case Sys::Platform::OS
|
16
|
-
when :windows
|
17
|
-
return(MiqLargeFileWin32.new(file_name, flags))
|
18
14
|
when :unix
|
19
15
|
if Sys::Platform::IMPL == :linux
|
20
16
|
return(RawBlockIO.new(file_name, flags)) if MiqLargeFileStat.new(file_name).blockdev?
|
@@ -26,17 +22,10 @@ module MiqLargeFile
|
|
26
22
|
end
|
27
23
|
|
28
24
|
def self.size(file_name)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
File.size(file_name)
|
34
|
-
else
|
35
|
-
f = open(file_name, "r")
|
36
|
-
s = f.size
|
37
|
-
f.close
|
38
|
-
return s
|
39
|
-
end
|
25
|
+
f = open(file_name, "r")
|
26
|
+
s = f.size
|
27
|
+
f.close
|
28
|
+
s
|
40
29
|
end
|
41
30
|
|
42
31
|
# For camcorder interposition.
|
@@ -158,8 +158,7 @@ class VmConfig
|
|
158
158
|
end
|
159
159
|
|
160
160
|
def set_vmconfig_path(config_path)
|
161
|
-
|
162
|
-
@configFile = ds.nil? ? File.normalize(config_path) : config_path
|
161
|
+
@configFile = normalize_vmconfig_file(config_path)
|
163
162
|
@configPath = File.dirname(@configFile)
|
164
163
|
end
|
165
164
|
|
@@ -255,6 +254,13 @@ class VmConfig
|
|
255
254
|
|
256
255
|
private
|
257
256
|
|
257
|
+
def normalize_vmconfig_file(config_file)
|
258
|
+
ds, _dir, _name = split_filename(config_file)
|
259
|
+
return config_file unless ds.nil?
|
260
|
+
|
261
|
+
File.expand_path(config_file.tr('\\', '/'))
|
262
|
+
end
|
263
|
+
|
258
264
|
def diskKey?(key)
|
259
265
|
key =~ /^ide\d+:\d+\.filename$/ || key =~ /^scsi\d+:\d+\.filename$/
|
260
266
|
end
|
@@ -446,7 +452,7 @@ class VmConfig
|
|
446
452
|
@files = []
|
447
453
|
if @direct_file_access
|
448
454
|
Dir.glob(File.join(@configPath, "/*.*")) do |f|
|
449
|
-
s = File.
|
455
|
+
s = File.size(f) rescue 0
|
450
456
|
@files << {:path => f, :name => File.basename(f), :size => s, :mtime => File.mtime(f)}
|
451
457
|
end
|
452
458
|
else
|
@@ -13,7 +13,6 @@ require 'metadata/util/win32/peheader'
|
|
13
13
|
require 'metadata/util/win32/remote-registry'
|
14
14
|
|
15
15
|
# Dev needs this.
|
16
|
-
require 'Win32API' if Sys::Platform::OS == :windows
|
17
16
|
require 'metadata/util/win32/system_path_win'
|
18
17
|
|
19
18
|
require 'digest/md5'
|
@@ -149,7 +148,7 @@ class Win32EventLog
|
|
149
148
|
|
150
149
|
# If an MiqFS instance was not passed, then the OS has to be (or emulate) Win32.
|
151
150
|
# If an MiqFS instance *was* passed, then if the guest OS is not Windows then getSystemRoot will throw.
|
152
|
-
raise "#{self.class}::initialize:
|
151
|
+
raise "#{self.class}::initialize: Filesystem is not MiqFS: cannot continue" if !vmMiqFs.class.to_s.include?('Miq')
|
153
152
|
|
154
153
|
# Get a file system instance if we don't already have one.
|
155
154
|
@fs = vmMiqFs
|
data/manageiq-smartstate.gemspec
CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
+
spec.add_dependency "azure-armrest"
|
24
|
+
spec.add_dependency "binary_struct", "~> 2.1"
|
23
25
|
spec.add_dependency "iniparse"
|
24
26
|
spec.add_dependency "linux_block_device", "~>0.2.1"
|
25
27
|
spec.add_dependency "memory_buffer", ">=0.1.0"
|
@@ -33,6 +35,7 @@ Gem::Specification.new do |spec|
|
|
33
35
|
spec.add_development_dependency "vcr", "~>3.0.2"
|
34
36
|
spec.add_development_dependency "webmock", "~>2.3.1"
|
35
37
|
spec.add_development_dependency "simplecov"
|
38
|
+
spec.add_development_dependency "rubocop"
|
36
39
|
spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0.0"
|
37
40
|
|
38
41
|
end
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manageiq-smartstate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ManageIQ Developers
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: azure-armrest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: binary_struct
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: iniparse
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,6 +206,20 @@ dependencies:
|
|
178
206
|
- - ">="
|
179
207
|
- !ruby/object:Gem::Version
|
180
208
|
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rubocop
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
181
223
|
- !ruby/object:Gem::Dependency
|
182
224
|
name: codeclimate-test-reporter
|
183
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,9 +240,13 @@ executables: []
|
|
198
240
|
extensions: []
|
199
241
|
extra_rdoc_files: []
|
200
242
|
files:
|
243
|
+
- ".codeclimate.yml"
|
201
244
|
- ".gitignore"
|
202
245
|
- ".rspec"
|
203
246
|
- ".rspec_ci"
|
247
|
+
- ".rubocop.yml"
|
248
|
+
- ".rubocop_cc.yml"
|
249
|
+
- ".rubocop_local.yml"
|
204
250
|
- ".travis.yml"
|
205
251
|
- Gemfile
|
206
252
|
- LICENSE.txt
|
@@ -271,6 +317,8 @@ files:
|
|
271
317
|
- lib/disk/camcorder_test.rb
|
272
318
|
- lib/disk/dos_mbr.img
|
273
319
|
- lib/disk/modules/AzureBlobDisk.rb
|
320
|
+
- lib/disk/modules/AzureDiskCommon.rb
|
321
|
+
- lib/disk/modules/AzureManagedDisk.rb
|
274
322
|
- lib/disk/modules/LocalDevMod.rb
|
275
323
|
- lib/disk/modules/LocalDevProbe.rb
|
276
324
|
- lib/disk/modules/MSCommon.rb
|
@@ -279,7 +327,6 @@ files:
|
|
279
327
|
- lib/disk/modules/MSVSDynamicDisk.rb
|
280
328
|
- lib/disk/modules/MSVSFixedDisk.rb
|
281
329
|
- lib/disk/modules/MiqLargeFile.rb
|
282
|
-
- lib/disk/modules/MiqLargeFileWin32.rb
|
283
330
|
- lib/disk/modules/QcowDisk.rb
|
284
331
|
- lib/disk/modules/QcowDiskProbe.rb
|
285
332
|
- lib/disk/modules/RawBlockIO.rb
|
@@ -521,7 +568,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
521
568
|
version: '0'
|
522
569
|
requirements: []
|
523
570
|
rubyforge_project:
|
524
|
-
rubygems_version: 2.6.
|
571
|
+
rubygems_version: 2.6.12
|
525
572
|
signing_key:
|
526
573
|
specification_version: 4
|
527
574
|
summary: ManageIQ SmartState Analysis
|
@@ -1,107 +0,0 @@
|
|
1
|
-
require 'memory_buffer'
|
2
|
-
require 'Win32API'
|
3
|
-
|
4
|
-
class MiqLargeFileWin32
|
5
|
-
# Access specifiers.
|
6
|
-
GENERIC_READ = 0x80000000
|
7
|
-
GENERIC_WRITE = 0x40000000
|
8
|
-
|
9
|
-
# Share specifiers.
|
10
|
-
FILE_SHARE_READ = 0x00000001
|
11
|
-
FILE_SHARE_WRITE = 0x00000002
|
12
|
-
|
13
|
-
# Creation disposition specifiers.
|
14
|
-
OPEN_EXISTING = 3
|
15
|
-
|
16
|
-
# Seek origin.
|
17
|
-
FILE_BEGIN = 0
|
18
|
-
FILE_CURRENT = 1
|
19
|
-
FILE_END = 2
|
20
|
-
|
21
|
-
# Misc.
|
22
|
-
INVALID_HANDLE_VALUE = -1
|
23
|
-
|
24
|
-
# API.
|
25
|
-
@@createFile = Win32API.new('kernel32', 'CreateFileA', 'PLLLLLL', 'L')
|
26
|
-
@@setFilePointerEx = Win32API.new('kernel32', 'SetFilePointerEx', 'LLLPL', 'L')
|
27
|
-
@@readFile = Win32API.new('kernel32', 'ReadFile', 'LPLPL', 'L')
|
28
|
-
@@writeFile = Win32API.new('kernel32', 'WriteFile', 'LPLPL', 'L')
|
29
|
-
@@closeHandle = Win32API.new('kernel32', 'CloseHandle', 'L', 'L')
|
30
|
-
@@getFileSize = Win32API.new('kernel32', 'GetFileSizeEx', 'LP', 'L')
|
31
|
-
@@getLastError = Win32API.new('kernel32', 'GetLastError', nil, 'L')
|
32
|
-
|
33
|
-
# Default constructor.
|
34
|
-
def initialize(file, access = "r")
|
35
|
-
accessOptions = 0
|
36
|
-
accessOptions |= GENERIC_READ if access.include?("r")
|
37
|
-
accessOptions |= GENERIC_WRITE if access.include?("+")
|
38
|
-
@hFile = @@createFile.call(file, accessOptions, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
|
39
|
-
raise "Couldn't open file #{file}" if @hFile == INVALID_HANDLE_VALUE
|
40
|
-
$log.debug("MiqLargeFile<#{object_id}> Opening #{file}, handle 0x#{'%08x' % @hFile}") if $log
|
41
|
-
end
|
42
|
-
|
43
|
-
# Alternative initialization.
|
44
|
-
def self.open(file, access = "r")
|
45
|
-
initialize(file, access)
|
46
|
-
end
|
47
|
-
|
48
|
-
def size
|
49
|
-
siz = MemoryBuffer.create_quad
|
50
|
-
err = @@getFileSize.call(@hFile, siz)
|
51
|
-
siz.unpack('Q')[0]
|
52
|
-
end
|
53
|
-
|
54
|
-
def seek(offset, whence)
|
55
|
-
method = case whence
|
56
|
-
when IO::SEEK_SET then FILE_BEGIN
|
57
|
-
when IO::SEEK_CUR then FILE_CURRENT
|
58
|
-
when IO::SEEK_END then FILE_END
|
59
|
-
else raise "Invalid seek method: #{whence}"
|
60
|
-
end
|
61
|
-
offHi, offLo = offset.divmod(4294967296) # 2 ** 32
|
62
|
-
new_pos = MemoryBuffer.create_quad
|
63
|
-
res = @@setFilePointerEx.call(@hFile, offLo, offHi, new_pos, method)
|
64
|
-
if res == 0
|
65
|
-
last_error = @@getLastError.call
|
66
|
-
raise "SetFilePointerEx failed - Offset:[#{offset}] method:[#{whence}] Handle:[0x#{'%08x' % @hFile}] GetLastErrorNum:[#{last_error}]"
|
67
|
-
end
|
68
|
-
new_pos = new_pos.unpack('Q')[0]
|
69
|
-
new_pos
|
70
|
-
end
|
71
|
-
|
72
|
-
def read(bytes)
|
73
|
-
# puts "#{getFilePos}, #{bytes}" if $track_pos
|
74
|
-
buf = MemoryBuffer.create(bytes)
|
75
|
-
bytesRead = MemoryBuffer.create_long
|
76
|
-
res = @@readFile.call(@hFile, buf, bytes, bytesRead, 0)
|
77
|
-
bytesRead = bytesRead.unpack('L')[0]
|
78
|
-
if bytesRead == 0 && bytes != 0 || res == 0
|
79
|
-
last_error = @@getLastError.call
|
80
|
-
raise "Read from disk file failed - result:[#{res}] bytesRead:[#{bytesRead}] expected:[#{bytes}] file pointer:[#{getFilePos}] file size:[#{size}] Handle:[0x#{'%08x' % @hFile}] GetLastErrorNum:[#{last_error}]."
|
81
|
-
end
|
82
|
-
buf = buf[0...bytesRead] if bytesRead != bytes
|
83
|
-
buf
|
84
|
-
end
|
85
|
-
|
86
|
-
def write(buf, len)
|
87
|
-
# NOTE: len must be a double word.
|
88
|
-
bytesWritten = MemoryBuffer.create_long
|
89
|
-
res = @@writeFile.call(@hFile, buf, len, bytesWritten, 0)
|
90
|
-
raise "WriteFile failed" if res == 0
|
91
|
-
bytesWritten = bytesWritten.unpack('L')[0]
|
92
|
-
raise "Not all data written" if bytesWritten != len
|
93
|
-
bytesWritten
|
94
|
-
end
|
95
|
-
|
96
|
-
def close
|
97
|
-
$log.debug("MiqLargeFile<#{object_id}> Closing handle 0x#{'%08x' % @hFile}") if $log
|
98
|
-
h = @hFile
|
99
|
-
res = @@closeHandle.call(@hFile)
|
100
|
-
@hFile = INVALID_HANDLE_VALUE if res != 0
|
101
|
-
return res, h
|
102
|
-
end
|
103
|
-
|
104
|
-
def getFilePos
|
105
|
-
seek(0, IO::SEEK_CUR)
|
106
|
-
end
|
107
|
-
end
|