fog-hyperv 0.0.9 → 0.1.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/README.md +12 -2
- data/lib/fog/bin/hyperv.rb +6 -4
- data/lib/fog/hyperv/collection.rb +89 -0
- data/lib/fog/hyperv/compute/models/bios.rb +70 -0
- data/lib/fog/hyperv/compute/models/cluster.rb +60 -0
- data/lib/fog/hyperv/compute/models/clusters.rb +21 -0
- data/lib/fog/hyperv/compute/models/com_port.rb +78 -0
- data/lib/fog/hyperv/compute/models/com_ports.rb +29 -0
- data/lib/fog/hyperv/compute/models/dvd_drive.rb +126 -0
- data/lib/fog/hyperv/compute/models/dvd_drives.rb +29 -0
- data/lib/fog/hyperv/compute/models/firmware.rb +78 -0
- data/lib/fog/hyperv/compute/models/floppy_drive.rb +64 -0
- data/lib/fog/hyperv/compute/models/floppy_drives.rb +18 -0
- data/lib/fog/hyperv/compute/models/hard_drive.rb +187 -0
- data/lib/fog/hyperv/compute/models/hard_drives.rb +28 -0
- data/lib/fog/hyperv/compute/models/host.rb +66 -0
- data/lib/fog/hyperv/compute/models/hosts.rb +13 -0
- data/lib/fog/hyperv/compute/models/network_adapter.rb +362 -0
- data/lib/fog/hyperv/compute/models/network_adapter_vlan.rb +172 -0
- data/lib/fog/hyperv/compute/models/network_adapters.rb +32 -0
- data/lib/fog/hyperv/compute/models/security.rb +121 -0
- data/lib/fog/hyperv/compute/models/server.rb +466 -0
- data/lib/fog/hyperv/compute/models/servers.rb +18 -0
- data/lib/fog/hyperv/compute/models/switch.rb +117 -0
- data/lib/fog/hyperv/compute/models/switches.rb +20 -0
- data/lib/fog/hyperv/compute/models/vhd.rb +210 -0
- data/lib/fog/hyperv/compute/models/vhds.rb +28 -0
- data/lib/fog/hyperv/compute/requests/add_vm_dvd_drive.rb +15 -0
- data/lib/fog/hyperv/compute/requests/add_vm_hard_disk_drive.rb +15 -0
- data/lib/fog/hyperv/compute/requests/add_vm_network_adapter.rb +24 -0
- data/lib/fog/hyperv/compute/requests/connect_vm_network_adapter.rb +41 -0
- data/lib/fog/hyperv/compute/requests/disable_vm_tpm.rb +16 -0
- data/lib/fog/hyperv/compute/requests/disconnect_vm_network_adapter.rb +29 -0
- data/lib/fog/hyperv/compute/requests/enable_vm_tpm.rb +16 -0
- data/lib/fog/hyperv/compute/requests/get_cluster.rb +11 -0
- data/lib/fog/hyperv/compute/requests/get_cluster_node.rb +22 -0
- data/lib/fog/hyperv/compute/requests/get_vhd.rb +32 -0
- data/lib/fog/hyperv/compute/requests/get_vm.rb +18 -0
- data/lib/fog/hyperv/compute/requests/get_vm_bios.rb +21 -0
- data/lib/fog/hyperv/compute/requests/get_vm_com_port.rb +17 -0
- data/lib/fog/hyperv/compute/requests/get_vm_dvd_drive.rb +25 -0
- data/lib/fog/hyperv/compute/requests/get_vm_firmware.rb +21 -0
- data/lib/fog/hyperv/compute/requests/get_vm_floppy_disk_drive.rb +16 -0
- data/lib/fog/hyperv/compute/requests/get_vm_group.rb +20 -0
- data/lib/fog/hyperv/compute/requests/get_vm_hard_disk_drive.rb +24 -0
- data/lib/fog/hyperv/compute/requests/get_vm_host.rb +9 -0
- data/lib/fog/hyperv/compute/requests/get_vm_host_cluster.rb +21 -0
- data/lib/fog/hyperv/compute/requests/get_vm_host_sbt.rb +10 -0
- data/lib/fog/hyperv/compute/requests/get_vm_key_protector.rb +16 -0
- data/lib/fog/hyperv/compute/requests/get_vm_network_adapter.rb +41 -0
- data/lib/fog/hyperv/compute/requests/get_vm_network_adapter_vlan.rb +41 -0
- data/lib/fog/hyperv/compute/requests/get_vm_security.rb +15 -0
- data/lib/fog/hyperv/compute/requests/get_vm_switch.rb +10 -0
- data/lib/fog/hyperv/compute/requests/mock_files/get_vm.json +4 -0
- data/lib/fog/hyperv/compute/requests/new_vhd.rb +9 -0
- data/lib/fog/hyperv/compute/requests/new_vm.rb +12 -0
- data/lib/fog/hyperv/compute/requests/new_vm_switch.rb +11 -0
- data/lib/fog/hyperv/compute/requests/optimize_vhd.rb +9 -0
- data/lib/fog/hyperv/compute/requests/remove_item.rb +10 -0
- data/lib/fog/hyperv/compute/requests/remove_vm.rb +16 -0
- data/lib/fog/hyperv/compute/requests/remove_vm_dvd_drive.rb +17 -0
- data/lib/fog/hyperv/compute/requests/remove_vm_hard_disk_drive.rb +17 -0
- data/lib/fog/hyperv/compute/requests/remove_vm_network_adapter.rb +29 -0
- data/lib/fog/hyperv/compute/requests/remove_vm_switch.rb +9 -0
- data/lib/fog/hyperv/compute/requests/rename_vm.rb +16 -0
- data/lib/fog/hyperv/compute/requests/rename_vm_network_adapter.rb +25 -0
- data/lib/fog/hyperv/compute/requests/rename_vm_switch.rb +9 -0
- data/lib/fog/hyperv/compute/requests/resize_vhd.rb +9 -0
- data/lib/fog/hyperv/compute/requests/restart_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/resume_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/save_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/set_vm.rb +15 -0
- data/lib/fog/hyperv/compute/requests/set_vm_bios.rb +15 -0
- data/lib/fog/hyperv/compute/requests/set_vm_com_port.rb +16 -0
- data/lib/fog/hyperv/compute/requests/set_vm_dvd_drive.rb +16 -0
- data/lib/fog/hyperv/compute/requests/set_vm_firmware.rb +15 -0
- data/lib/fog/hyperv/compute/requests/set_vm_floppy_disk_drive.rb +16 -0
- data/lib/fog/hyperv/compute/requests/set_vm_hard_disk_drive.rb +16 -0
- data/lib/fog/hyperv/compute/requests/set_vm_key_protector.rb +15 -0
- data/lib/fog/hyperv/compute/requests/set_vm_network_adapter.rb +25 -0
- data/lib/fog/hyperv/compute/requests/set_vm_network_adapter_vlan.rb +25 -0
- data/lib/fog/hyperv/compute/requests/set_vm_security.rb +17 -0
- data/lib/fog/hyperv/compute/requests/set_vm_switch.rb +9 -0
- data/lib/fog/hyperv/compute/requests/start_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/stop_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/suspend_vm.rb +22 -0
- data/lib/fog/hyperv/compute/requests/update_vm.rb +22 -0
- data/lib/fog/hyperv/compute.rb +206 -387
- data/lib/fog/hyperv/constants.rb +24 -0
- data/lib/fog/hyperv/fog_extensions/associations/collection.rb +11 -0
- data/lib/fog/hyperv/fog_extensions/attributes/datetime.rb +28 -0
- data/lib/fog/hyperv/fog_extensions/attributes/enum.rb +139 -0
- data/lib/fog/hyperv/fog_extensions/attributes/enumarray.rb +149 -0
- data/lib/fog/hyperv/fog_extensions/attributes/timespan.rb +27 -0
- data/lib/fog/hyperv/model.rb +142 -0
- data/lib/fog/hyperv/utils/powershell.rb +88 -0
- data/lib/fog/hyperv/utils/winrm.rb +233 -0
- data/lib/fog/hyperv/version.rb +4 -1
- data/lib/fog/hyperv.rb +51 -44
- metadata +187 -105
- data/.gitignore +0 -10
- data/.travis.yml +0 -11
- data/CHANGELOG.md +0 -52
- data/Gemfile +0 -4
- data/Rakefile +0 -10
- data/fog-hyperv.gemspec +0 -25
- data/lib/fog/collection.rb +0 -152
- data/lib/fog/hyperv/fog_extensions/enum.rb +0 -85
- data/lib/fog/hyperv/models/compute/bios.rb +0 -61
- data/lib/fog/hyperv/models/compute/cluster.rb +0 -64
- data/lib/fog/hyperv/models/compute/clusters.rb +0 -15
- data/lib/fog/hyperv/models/compute/com_port.rb +0 -22
- data/lib/fog/hyperv/models/compute/dvd_drive.rb +0 -92
- data/lib/fog/hyperv/models/compute/dvd_drives.rb +0 -12
- data/lib/fog/hyperv/models/compute/firmware.rb +0 -53
- data/lib/fog/hyperv/models/compute/floppy_drive.rb +0 -53
- data/lib/fog/hyperv/models/compute/floppy_drives.rb +0 -12
- data/lib/fog/hyperv/models/compute/hard_drive.rb +0 -110
- data/lib/fog/hyperv/models/compute/hard_drives.rb +0 -11
- data/lib/fog/hyperv/models/compute/host.rb +0 -45
- data/lib/fog/hyperv/models/compute/hosts.rb +0 -15
- data/lib/fog/hyperv/models/compute/network_adapter.rb +0 -145
- data/lib/fog/hyperv/models/compute/network_adapters.rb +0 -19
- data/lib/fog/hyperv/models/compute/server.rb +0 -220
- data/lib/fog/hyperv/models/compute/servers.rb +0 -21
- data/lib/fog/hyperv/models/compute/switch.rb +0 -65
- data/lib/fog/hyperv/models/compute/switches.rb +0 -15
- data/lib/fog/hyperv/models/compute/vhd.rb +0 -101
- data/lib/fog/hyperv/models/compute/vhds.rb +0 -16
- data/lib/fog/hyperv/requests/compute/add_vm_dvd_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/add_vm_hard_disk_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/add_vm_network_adapter.rb +0 -12
- data/lib/fog/hyperv/requests/compute/connect_vm_network_adapter.rb +0 -12
- data/lib/fog/hyperv/requests/compute/disconnect_vm_network_adapter.rb +0 -12
- data/lib/fog/hyperv/requests/compute/get_cluster.rb +0 -11
- data/lib/fog/hyperv/requests/compute/get_cluster_node.rb +0 -19
- data/lib/fog/hyperv/requests/compute/get_vhd.rb +0 -34
- data/lib/fog/hyperv/requests/compute/get_vm.rb +0 -20
- data/lib/fog/hyperv/requests/compute/get_vm_bios.rb +0 -21
- data/lib/fog/hyperv/requests/compute/get_vm_dvd_drive.rb +0 -20
- data/lib/fog/hyperv/requests/compute/get_vm_firmware.rb +0 -19
- data/lib/fog/hyperv/requests/compute/get_vm_floppy_disk_drive.rb +0 -20
- data/lib/fog/hyperv/requests/compute/get_vm_group.rb +0 -23
- data/lib/fog/hyperv/requests/compute/get_vm_hard_disk_drive.rb +0 -20
- data/lib/fog/hyperv/requests/compute/get_vm_host.rb +0 -12
- data/lib/fog/hyperv/requests/compute/get_vm_host_cluster.rb +0 -25
- data/lib/fog/hyperv/requests/compute/get_vm_network_adapter.rb +0 -27
- data/lib/fog/hyperv/requests/compute/get_vm_switch.rb +0 -27
- data/lib/fog/hyperv/requests/compute/mock_files/get_vm.json +0 -1
- data/lib/fog/hyperv/requests/compute/new_vhd.rb +0 -12
- data/lib/fog/hyperv/requests/compute/new_vm.rb +0 -15
- data/lib/fog/hyperv/requests/compute/new_vm_switch.rb +0 -13
- data/lib/fog/hyperv/requests/compute/remove_item.rb +0 -13
- data/lib/fog/hyperv/requests/compute/remove_vm.rb +0 -15
- data/lib/fog/hyperv/requests/compute/remove_vm_dvd_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/remove_vm_hard_disk_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/remove_vm_network_adapter.rb +0 -12
- data/lib/fog/hyperv/requests/compute/restart_vm.rb +0 -15
- data/lib/fog/hyperv/requests/compute/set_vm.rb +0 -12
- data/lib/fog/hyperv/requests/compute/set_vm_bios.rb +0 -13
- data/lib/fog/hyperv/requests/compute/set_vm_dvd_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/set_vm_firmware.rb +0 -13
- data/lib/fog/hyperv/requests/compute/set_vm_hard_disk_drive.rb +0 -12
- data/lib/fog/hyperv/requests/compute/set_vm_network_adapter.rb +0 -12
- data/lib/fog/hyperv/requests/compute/set_vm_network_adapter_vlan.rb +0 -12
- data/lib/fog/hyperv/requests/compute/set_vm_switch.rb +0 -13
- data/lib/fog/hyperv/requests/compute/start_vm.rb +0 -15
- data/lib/fog/hyperv/requests/compute/stop_vm.rb +0 -15
- data/lib/fog/model.rb +0 -91
- data/test/fog/hyperv_test.rb +0 -7
- data/test/test_helper.rb +0 -4
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_cluster.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_cluster_node.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vhd.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_bios.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_dvd_drive.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_firmware.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_floppy_disk_drive.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_hard_disk_drive.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_host.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_network_adapter.json +0 -0
- /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_switch.json +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/ModuleLength
|
|
4
|
+
|
|
5
|
+
# WinRM helper methods
|
|
6
|
+
module Fog::Hyperv::Utils::Winrm
|
|
7
|
+
# Struct emulating a WinRM shell return
|
|
8
|
+
LocalExecOutput = Struct.new(:stdout, :stderr, :exitcode)
|
|
9
|
+
|
|
10
|
+
# Check if the PowerShell version is newer than the value specified
|
|
11
|
+
# @param version [String] a semver version to check if powershell matches
|
|
12
|
+
# @returns [Boolean] is the running PowerShell newer than the given version
|
|
13
|
+
def ps_version?(version)
|
|
14
|
+
Gem::Version(version) >= Gem::Version("#{ps_version[:major]}.#{ps_version[:minor]}")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Run a command on the Hyper-V system
|
|
18
|
+
# @param cmd [String] the PowerShell command to execute
|
|
19
|
+
# @param _skip_json [Boolean] should the return data be returned as-is, instead of being sent as JSON
|
|
20
|
+
# @param _target_computer [String,nil] the computer to execute the command on, in case of clustering
|
|
21
|
+
# @param options [Hash] the options to call the command with
|
|
22
|
+
# @option options [Integer] _json_depth (1) the depth to limit the JSON object to on return
|
|
23
|
+
# @return [Hash] the returned object from PowerShell
|
|
24
|
+
def run_cmd(cmd, _skip_json: false, _target_computer: nil, **options)
|
|
25
|
+
_json_depth = options.delete(:_json_depth) { 1 }
|
|
26
|
+
|
|
27
|
+
run_cmdlist([[cmd, options.dup]], skip_json: _skip_json, json_depth: _json_depth, target_computer: _target_computer)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Run a list of commands on the Hyper-V system
|
|
31
|
+
# @param commands [Array<Array(String,Hash)>] a list of commands with their arguments to run
|
|
32
|
+
# @param skip_json [Boolean] should the return value be given as-is, instead of being sent as JSON
|
|
33
|
+
# @param target_computer [String,nil] the computer to execute the command on, in case of clustering
|
|
34
|
+
# @param separate_calls [Boolean] should the commands be run separately
|
|
35
|
+
# @param options [Hash] additional options for the call
|
|
36
|
+
# @option options [Integer] json_depth (1) the depth to limit the JSON object to on return
|
|
37
|
+
def run_cmdlist(commands, skip_json: false, target_computer: nil, separate_calls: false, **options)
|
|
38
|
+
target_computer = [target_computer].flatten.compact
|
|
39
|
+
target_computer << '.' if target_computer.empty?
|
|
40
|
+
|
|
41
|
+
json_depth = options.delete(:json_depth) { 1 }
|
|
42
|
+
|
|
43
|
+
Fog::Logger.debug "run_cmdlist given unknown meta-arguments: #{options.keys.join ', '}" if options.any?
|
|
44
|
+
|
|
45
|
+
out = nil
|
|
46
|
+
target_computer.each do |computer|
|
|
47
|
+
connection(computer).shell(:powershell) do |shell|
|
|
48
|
+
# Avoid confirmation questions, abort early on errors
|
|
49
|
+
setup = [
|
|
50
|
+
"$ConfirmPreference = 'None'",
|
|
51
|
+
"$ErrorActionPreference = 'Stop'",
|
|
52
|
+
'$PSNativeCommandUseErrorActionPreference = $true'
|
|
53
|
+
].join('; ')
|
|
54
|
+
shell.run setup
|
|
55
|
+
|
|
56
|
+
pscalls = commands.map.with_index do |(command, args), idx|
|
|
57
|
+
last = idx == commands.size - 1
|
|
58
|
+
build_pscall(command, _to_json: last && !skip_json, _json_depth: json_depth, **args)
|
|
59
|
+
end
|
|
60
|
+
pscalls = [pscalls.join("\n")] unless separate_calls
|
|
61
|
+
|
|
62
|
+
pscalls.each do |cmd|
|
|
63
|
+
Fog::Logger.debug "PS; >>> \"#{cmd.split("\n").join("\n\t")}\""
|
|
64
|
+
out = shell.run cmd
|
|
65
|
+
Fog::Logger.debug "PS; <<< OUT=[#{out.stdout.inspect}] ERR=[#{out.stderr.inspect}] EXIT=[#{out.exitcode}]"
|
|
66
|
+
|
|
67
|
+
is_success = true
|
|
68
|
+
is_success = shell.run('$?').stdout.strip.downcase == 'true' if out.stderr.include? 'FullyQualifiedErrorId'
|
|
69
|
+
|
|
70
|
+
raise Fog::Hyperv::Errors::PSError.new(out, "When executing #{cmd}") if
|
|
71
|
+
out.exitcode != 0 || !is_success
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return out if skip_json
|
|
77
|
+
return nil if out.stdout.strip.empty?
|
|
78
|
+
|
|
79
|
+
json = Fog::JSON.decode(out.stdout)
|
|
80
|
+
Fog::Hyperv.uncamelize(json)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Perform a WQL query against the Hyper-V system
|
|
84
|
+
# @param query [String] the query to perform
|
|
85
|
+
# @param _namespace [String] the namespace to perform the call in
|
|
86
|
+
# @param where [Hash] the WHERE arguments to add to the query
|
|
87
|
+
# @return [Hash] the return hash from the WQL query
|
|
88
|
+
def run_wql(query, _namespace: 'root/virtualization/v2', **where)
|
|
89
|
+
args = Fog::Hyperv.camelize(where).reject { |k, v| v.nil? || v.is_a?(FalseClass) || k.to_s.start_with?('_') }.map do |k, v|
|
|
90
|
+
"#{k} = #{((v.is_a?(String) || v.to_s =~ /\s/) && v.inspect) || v}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
query = "#{query}#{" WHERE #{args.join ' AND '}" unless args.none?}"
|
|
94
|
+
|
|
95
|
+
Fog::Logger.debug "WQL; in #{_namespace} >>> #{query}"
|
|
96
|
+
data =
|
|
97
|
+
if local?
|
|
98
|
+
raise NotImplementedError, 'Not implemented for local connection'
|
|
99
|
+
# run_cmd('Get-WmiObject', query:, namespace:, _return_fields: options.keys)
|
|
100
|
+
else
|
|
101
|
+
@connection.run_wql(query, "#{_namespace}/*")[:xml_fragment].first
|
|
102
|
+
end
|
|
103
|
+
Fog::Logger.debug "WQL; <<< #{data}"
|
|
104
|
+
|
|
105
|
+
data
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def version
|
|
111
|
+
@version ||= begin
|
|
112
|
+
run_wql('SELECT Version FROM Win32_OperatingSystem', _namespace: 'root/cimv2')[:version]
|
|
113
|
+
rescue StandardError
|
|
114
|
+
run_cmd(
|
|
115
|
+
<<~CMD,
|
|
116
|
+
$VMMS = if ([environment]::Is64BitProcess) {
|
|
117
|
+
"$($env:SystemRoot)\\System32\\vmms.exe"
|
|
118
|
+
} else {
|
|
119
|
+
"$($env:SystemRoot)\\Sysnative\\vmms.exe"
|
|
120
|
+
}
|
|
121
|
+
(Get-Item $VMMS).VersionInfo.ProductVersion"
|
|
122
|
+
CMD
|
|
123
|
+
_skip_json: true,
|
|
124
|
+
_ps_version: 1
|
|
125
|
+
).stdout.strip
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def ps_version
|
|
130
|
+
@ps_version ||= run_cmd('$PSVersionTable.PSVersion', _ps_version: 1)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def build_pscall(command, _by_id: nil, _return_fields: nil, _always_include: [], **options)
|
|
134
|
+
_ps_version = options.delete(:_ps_version) { ps_version[:major] }
|
|
135
|
+
_to_json = options.delete(:_to_json) { true }
|
|
136
|
+
_json_depth = options.delete(:_json_depth) { 1 }
|
|
137
|
+
|
|
138
|
+
pipeline = []
|
|
139
|
+
pipeline << "Where-Object {$_.id -eq '#{_by_id}'}" if _by_id
|
|
140
|
+
pipeline << "Select #{Fog::Hyperv.camelize([_return_fields].flatten).join ','}" if _return_fields
|
|
141
|
+
pipeline << "ConvertTo-Json -Compress#{" -Depth #{_json_depth}" if _json_depth}" if _to_json
|
|
142
|
+
|
|
143
|
+
invalid_opts = options.select { |k, _| k.to_s.start_with? '_' }
|
|
144
|
+
Fog::Logger.debug "build_pscall given unexpected meta-arguments: #{invalid_opts.keys.join ', '}" if invalid_opts.any?
|
|
145
|
+
|
|
146
|
+
options.reject! { |k, _| k.to_s.start_with?('_') }
|
|
147
|
+
options.reject! do |k, v|
|
|
148
|
+
!_always_include.include?(k) && (v.nil? || v.is_a?(FalseClass) || k.to_s.start_with?('_') || (v.is_a?(String) && v.empty?))
|
|
149
|
+
end
|
|
150
|
+
options = Fog::Hyperv.camelize(options.compact)
|
|
151
|
+
|
|
152
|
+
command += ' @Args' unless command.include? '@Args'
|
|
153
|
+
pipeline = [command] + pipeline
|
|
154
|
+
Fog::Hyperv::Utils::Powershell.build_call(pipeline.join(' | '), options, _ps_version:)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def connection(host)
|
|
158
|
+
existing = @connections.find do |c_host, c_connection|
|
|
159
|
+
c_host.downcase.start_with?(host.downcase) ||
|
|
160
|
+
URI(c_connection.instance_variable_get(:@connection_opts)[:endpoint]).host.downcase.start_with?(host.downcase)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if existing
|
|
164
|
+
@connections[host] = existing unless @connections.key? host
|
|
165
|
+
return existing.last
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
if %w[. localhost].include? host
|
|
169
|
+
endpoint = @hyperv_endpoint
|
|
170
|
+
else
|
|
171
|
+
# TODO: Support non-standard endpoints for additional hosts
|
|
172
|
+
unless host.include? '.'
|
|
173
|
+
host = run_cmd("[System.Net.Dns]::GetHostByName(#{host.inspect})", _return_fields: :host_name, _ps_version: 1)[:host_name]
|
|
174
|
+
end
|
|
175
|
+
endpoint = "http://#{host}:5985/wsman"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
existing = @connections.find do |_, c_connection|
|
|
179
|
+
c_connection.instance_variable_get(:@connection_opts)[:endpoint] == endpoint
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
if existing
|
|
183
|
+
@connections[host] = existing unless @connections.key? host
|
|
184
|
+
return existing.last
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
connect(endpoint)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def connect(endpoint = nil)
|
|
191
|
+
endpoint ||= @hyperv_endpoint
|
|
192
|
+
fqdn = URI.parse(endpoint).host
|
|
193
|
+
|
|
194
|
+
require 'winrm'
|
|
195
|
+
|
|
196
|
+
opts = {
|
|
197
|
+
endpoint: endpoint,
|
|
198
|
+
transport: @hyperv_transport,
|
|
199
|
+
user: @hyperv_username,
|
|
200
|
+
password: @hyperv_password,
|
|
201
|
+
realm: @hyperv_realm,
|
|
202
|
+
no_ssl_peer_verification: true
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
Fog::Logger.debug "Creating WinRM connection with #{opts.merge password: '<REDACTED>'}"
|
|
206
|
+
connection = WinRM::Connection.new opts
|
|
207
|
+
connection.logger.level = :error
|
|
208
|
+
@connections[fqdn] = connection
|
|
209
|
+
|
|
210
|
+
# Add the local host's names to the connection
|
|
211
|
+
begin
|
|
212
|
+
hostname = run_cmd('$env:computerName', _target_computer: fqdn, _skip_json: true, _ps_version: 1).stdout.downcase.strip
|
|
213
|
+
@connections[hostname] ||= connection
|
|
214
|
+
fqdn = run_cmd(
|
|
215
|
+
'[System.Net.Dns]::GetHostByName(($env:computerName)).Hostname',
|
|
216
|
+
_target_computer: fqdn,
|
|
217
|
+
_skip_json: true,
|
|
218
|
+
_ps_version: 1
|
|
219
|
+
).stdout.downcase.strip
|
|
220
|
+
@connections[fqdn] ||= connection
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
if endpoint == @hyperv_endpoint
|
|
224
|
+
@connection = connection
|
|
225
|
+
@connections['.'] = connection
|
|
226
|
+
@connections['localhost'] = connection
|
|
227
|
+
@local_hostname = hostname
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
connection
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
# rubocop:enable Metrics/ModuleLength
|
data/lib/fog/hyperv/version.rb
CHANGED
data/lib/fog/hyperv.rb
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'fog/core'
|
|
2
4
|
|
|
3
5
|
module Fog
|
|
4
6
|
module Attributes
|
|
5
|
-
autoload :
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
autoload :Hyperv, File.expand_path('../hyperv/compute', __FILE__)
|
|
7
|
+
autoload :Hypervdatetime, File.expand_path('hyperv/fog_extensions/attributes/datetime.rb', __dir__)
|
|
8
|
+
autoload :Hypervenum, File.expand_path('hyperv/fog_extensions/attributes/enum.rb', __dir__)
|
|
9
|
+
autoload :Hypervenumarray, File.expand_path('hyperv/fog_extensions/attributes/enumarray.rb', __dir__)
|
|
10
|
+
autoload :Hypervtimespan, File.expand_path('hyperv/fog_extensions/attributes/timespan.rb', __dir__)
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
module Hyperv
|
|
14
|
+
require 'fog/hyperv/constants'
|
|
15
|
+
|
|
13
16
|
extend Fog::Provider
|
|
14
17
|
|
|
18
|
+
autoload :Compute, File.expand_path('hyperv/compute', __dir__)
|
|
19
|
+
|
|
15
20
|
module Errors
|
|
21
|
+
# A general service error occurred
|
|
16
22
|
class ServiceError < Fog::Errors::Error; end
|
|
23
|
+
|
|
24
|
+
# A version constrain was not matched
|
|
17
25
|
class VersionError < ServiceError
|
|
18
26
|
attr_reader :version, :required_version, :function
|
|
19
27
|
|
|
@@ -22,10 +30,11 @@ module Fog
|
|
|
22
30
|
@required_version = required_version
|
|
23
31
|
@version = version
|
|
24
32
|
|
|
25
|
-
super
|
|
33
|
+
super("#{function} requires at least Hyper-V v#{required_version}, you have v#{version}")
|
|
26
34
|
end
|
|
27
35
|
end
|
|
28
36
|
|
|
37
|
+
# A powershell call failed
|
|
29
38
|
class PSError < ServiceError
|
|
30
39
|
attr_reader :stdout, :stderr, :exitcode, :info, :message
|
|
31
40
|
|
|
@@ -34,51 +43,48 @@ module Fog
|
|
|
34
43
|
@stderr = output.stderr
|
|
35
44
|
@exitcode = output.exitcode
|
|
36
45
|
@info = info
|
|
37
|
-
|
|
38
|
-
super @message
|
|
39
|
-
end
|
|
46
|
+
extract_message
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
ret = [super]
|
|
43
|
-
ret << info unless info.nil? || info.empty?
|
|
44
|
-
ret.join "\n"
|
|
48
|
+
super(@message)
|
|
45
49
|
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
# def to_s
|
|
52
|
+
# ret = [super]
|
|
53
|
+
# ret << info unless info.nil? || info.empty?
|
|
54
|
+
# ret.join "\n"
|
|
55
|
+
# end
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
private
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.gsub(/\r/, '`r')
|
|
65
|
-
.inspect
|
|
66
|
-
.gsub(/\\"/, '`"')
|
|
67
|
-
.gsub(/\\\\/, '\\')
|
|
68
|
-
else
|
|
69
|
-
data
|
|
59
|
+
def extract_message
|
|
60
|
+
stderr = @stderr.split("\n").map(&:strip)
|
|
61
|
+
|
|
62
|
+
# Find a line ending in an error ID
|
|
63
|
+
@message = stderr.find { |line| line =~ /\(0x[0-9a-f]+\)\.?$/}
|
|
64
|
+
# Find the last line that isn't include error class information
|
|
65
|
+
@message ||= stderr.take_while { |line| !line.start_with? '+' }.last
|
|
70
66
|
end
|
|
71
|
-
when Array
|
|
72
|
-
'@(' + data.map { |e| shell_quoted(e, true) }.join(', ') + ')'
|
|
73
|
-
when FalseClass
|
|
74
|
-
'$false'
|
|
75
|
-
when TrueClass
|
|
76
|
-
'$true'
|
|
77
|
-
else
|
|
78
|
-
shell_quoted data.to_s
|
|
79
67
|
end
|
|
80
68
|
end
|
|
81
69
|
|
|
70
|
+
module Associations
|
|
71
|
+
autoload :Collection, File.expand_path('hyperv/fog_extensions/associations/collection', __dir__)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module Utils
|
|
75
|
+
autoload :Powershell, File.expand_path('hyperv/utils/powershell', __dir__)
|
|
76
|
+
autoload :Winrm, File.expand_path('hyperv/utils/winrm', __dir__)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
autoload :Collection, File.expand_path('hyperv/collection', __dir__)
|
|
80
|
+
autoload :Model, File.expand_path('hyperv/model', __dir__)
|
|
81
|
+
autoload :ModelExtends, File.expand_path('hyperv/model', __dir__)
|
|
82
|
+
autoload :ModelIncludes, File.expand_path('hyperv/model', __dir__)
|
|
83
|
+
autoload :VMCollection, File.expand_path('hyperv/collection', __dir__)
|
|
84
|
+
|
|
85
|
+
service(:compute, 'Compute')
|
|
86
|
+
|
|
87
|
+
# Convert a piece of data from being snake_case to being CamelCase
|
|
82
88
|
def self.camelize(data)
|
|
83
89
|
case data
|
|
84
90
|
when Array
|
|
@@ -86,7 +92,7 @@ module Fog
|
|
|
86
92
|
when Hash
|
|
87
93
|
data.each_with_object({}) do |(k, v), hash|
|
|
88
94
|
value = v
|
|
89
|
-
value = camelize(v) if v.is_a?(Hash) || (v.is_a?(Array) && v.all?
|
|
95
|
+
value = camelize(v) if v.is_a?(Hash) || (v.is_a?(Array) && v.all?(Hash))
|
|
90
96
|
hash[camelize(k)] = value
|
|
91
97
|
end
|
|
92
98
|
when Symbol
|
|
@@ -98,6 +104,7 @@ module Fog
|
|
|
98
104
|
end
|
|
99
105
|
end
|
|
100
106
|
|
|
107
|
+
# Convert a piece of data from being CamelCase to being snake_case
|
|
101
108
|
def self.uncamelize(data)
|
|
102
109
|
case data
|
|
103
110
|
when Array
|
|
@@ -105,7 +112,7 @@ module Fog
|
|
|
105
112
|
when Hash
|
|
106
113
|
data.each_with_object({}) do |(k, v), hash|
|
|
107
114
|
value = v
|
|
108
|
-
value = uncamelize(v) if v.is_a?(Hash) || (v.is_a?(Array) && v.all?
|
|
115
|
+
value = uncamelize(v) if v.is_a?(Hash) || (v.is_a?(Array) && v.all?(Hash))
|
|
109
116
|
hash[uncamelize(k)] = value
|
|
110
117
|
end
|
|
111
118
|
when Symbol
|