fog-hyperv 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 800c08e48379e123d5b8803ea3bda44f4eddbaa8
4
- data.tar.gz: df40fef67b97eeed7469c51710b12bec6b455f39
3
+ metadata.gz: 7d1f016acb31e48e1b25113f74c059dcd1d76eb2
4
+ data.tar.gz: a9fa8894c68b1520b9e244c92dee0fc0e2e899cc
5
5
  SHA512:
6
- metadata.gz: 0401b571330dad19781f5c35bfbc0cce18de2fdb02266583ba4ca2255b9c4a16e3c38b93303cfde9fa655ed0e73c0abf217dea43495a243460f2328ba42cbdac
7
- data.tar.gz: 718b6a478f911d0070427d486951125a2ddb8407475cbc2540c962bb90f64a45a7af4cb982c9bfd0f9bc09afab2238d71a52dd0f622a7541d27b9afc65ebf2dc
6
+ metadata.gz: ed4973a3d9d1c34e0c5e5374f5048f7d6f9a9f41b16084e9799061cc25109458599a498b98b2e37e7070b2e9f496100bf052297c8c146dcbda361fd2ed0d14b5
7
+ data.tar.gz: 2ef22b03209489609a1ac1190e530c2b5dd9a88f8f7838617987a38fca2d1f365763ff3f9fa9443bc170ca6ce700f71d20cb0f33a88d3807834945da12298bc5
@@ -1,14 +1,22 @@
1
- ## v0.0.3 2017-09-30
1
+ ## v0.0.4 2017-11-14
2
2
 
3
- - Fix handling of BIOS/Firmware
4
- - Skip unnecessary Hyper-V calls when checking dirty status
5
- - Add some possible interface improvements when dealing with clusters
3
+ - Adds support for the Kerberos transport
4
+ - Implements a first prototype for multi-hop when not using Kerberos/CredSSP
5
+ - Fixes issues in the saving of a few models
6
+ - Fixes a major issue when a VM ends up in a state with a large numerical value
7
+ - An issue in the enum code made input validity checking unable to differentiate between hashes and arrays
6
8
 
7
- ## v0.0.2 2017-09-28
9
+ ## v0.0.3 2017-08-30
8
10
 
9
- - Reduced `fog-core` dependency to 1.42
10
- - Disabled `status` attribute for network adapters, due to Hyper-V 6.3 issues
11
+ - Fixes handling of BIOS/Firmware
12
+ - Skips unnecessary Hyper-V calls when checking dirty status
13
+ - Adds some possible interface improvements when dealing with clusters
11
14
 
12
- ## v0.0.1 2017-09-25
15
+ ## v0.0.2 2017-08-28
16
+
17
+ - Reduces `fog-core` dependency to 1.42
18
+ - Disables `status` attribute for network adapters, due to Hyper-V 6.3 issues
19
+
20
+ ## v0.0.1 2017-08-25
13
21
 
14
22
  - Initial release
@@ -15,13 +15,6 @@ module Fog
15
15
  requires.include? req
16
16
  end
17
17
 
18
- def search_attributes
19
- attributes.dup.merge(
20
- _return_fields: model.attributes - model.lazy_attributes,
21
- _json_depth: 1
22
- )
23
- end
24
-
25
18
  def all(filters = {})
26
19
  requires(*self.class.requires)
27
20
  data = service.send(method, search_attributes.merge(filters))
@@ -34,13 +27,13 @@ module Fog
34
27
  data = all(filters).first
35
28
  data if data
36
29
  rescue Fog::Hyperv::Errors::PSError => err
37
- raise Fog::Errors::NotFound, err if err.message =~ /Hyper-V was unable to find|^No .* is found|/
30
+ raise Fog::Errors::NotFound, err if err.message =~ /Hyper-V was unable to find|^No .* is found/
38
31
  raise err
39
32
  end
40
33
 
41
34
  def new(options = {})
42
35
  requires(*self.class.requires)
43
- super(search_attributes.merge(options))
36
+ super(creation_attributes.merge(options))
44
37
  end
45
38
 
46
39
  def create(attributes = {})
@@ -49,6 +42,19 @@ module Fog
49
42
  object
50
43
  end
51
44
 
45
+ protected
46
+
47
+ def search_attributes
48
+ attributes.dup.merge(
49
+ _return_fields: model.attributes - model.lazy_attributes,
50
+ _json_depth: 1
51
+ )
52
+ end
53
+
54
+ def creation_attributes
55
+ attributes.dup
56
+ end
57
+
52
58
  private
53
59
 
54
60
  def method
@@ -64,11 +70,20 @@ module Fog
64
70
  attr_accessor :cluster
65
71
  attr_accessor :computer
66
72
 
73
+ protected
74
+
75
+ def creation_attributes
76
+ to_add = {}
77
+ to_add[:cluster] = cluster if cluster
78
+ to_add[:computer] = computer if computer
79
+ super.merge(to_add)
80
+ end
81
+
67
82
  def search_attributes
68
83
  attrs = super
69
84
  attrs.delete :cluster
70
85
  attrs.delete :computer
71
- attrs[:computer_name] ||= cluster.hosts.map { |n| n.name } if cluster
86
+ attrs[:computer_name] ||= cluster.hosts.map(&:name) if cluster
72
87
  attrs[:computer_name] ||= computer.name if computer
73
88
  attrs
74
89
  end
@@ -85,22 +100,11 @@ module Fog
85
100
 
86
101
  attr_accessor :vm
87
102
 
88
- def search_attributes
89
- attrs = super
90
- attrs.delete :vm
91
- if vm
92
- attrs[:computer_name] ||= vm.computer_name
93
- attrs[match] = vm.send(match)
94
- end
95
- attrs
96
- end
97
-
98
- def create(attributes = {})
99
- object = new(attributes)
103
+ def new(attributes = {})
104
+ object = super
100
105
  # Ensure both ID and Name are populated, regardless of `match_on`
101
106
  object.vm_id ||= vm.id if vm && object.respond_to?(:vm_id)
102
107
  object.vm_name ||= vm.name if vm && object.respond_to?(:vm_name)
103
- object.save
104
108
  object
105
109
  end
106
110
 
@@ -109,12 +113,27 @@ module Fog
109
113
  to_s
110
114
  end
111
115
 
112
- private
116
+ protected
117
+
118
+ def creation_attributes
119
+ to_add = {}
120
+ to_add[:vm] = vm if vm
113
121
 
114
- def logger
115
- service.logger
122
+ super.merge to_add
116
123
  end
117
124
 
125
+ def search_attributes
126
+ attrs = super
127
+ attrs.delete :vm
128
+ if vm
129
+ attrs[:computer_name] ||= vm.computer_name
130
+ attrs[match] = vm.send(match)
131
+ end
132
+ attrs
133
+ end
134
+
135
+ private
136
+
118
137
  def match
119
138
  self.class.match_on || :vm_name
120
139
  end
@@ -24,10 +24,12 @@ module Fog
24
24
  # :ProtocolVersion # 32775
25
25
  ].freeze
26
26
 
27
- requires :hyperv_username, :hyperv_password
27
+ requires :hyperv_username
28
28
  recognizes :hyperv_endpoint, :hyperv_host,
29
- :hyperv_transport,
29
+ :hyperv_password,
30
+ :hyperv_transport, :hyperv_realm,
30
31
  :hyperv_debug
32
+
31
33
  secrets :hyperv_password, :connection
32
34
 
33
35
  model_path 'fog/hyperv/models/compute'
@@ -54,6 +56,7 @@ module Fog
54
56
  collection :vhds
55
57
 
56
58
  request_path 'fog/hyperv/requests/compute'
59
+ request :add_vm_dvd_drive
57
60
  request :add_vm_hard_disk_drive
58
61
  request :add_vm_network_adapter
59
62
  request :connect_vm_network_adapter
@@ -77,6 +80,7 @@ module Fog
77
80
  request :new_vm_switch
78
81
  request :remove_item
79
82
  request :remove_vm
83
+ request :remove_vm_dvd_drive
80
84
  request :remove_vm_hard_disk_drive
81
85
  request :remove_vm_network_adapter
82
86
  request :restart_vm
@@ -135,11 +139,15 @@ module Fog
135
139
  require 'fog/json'
136
140
  require 'logging'
137
141
 
142
+ @connections = {}
138
143
  @hyperv_endpoint = options[:hyperv_endpoint]
139
144
  @hyperv_endpoint = "http://#{options[:hyperv_host]}:5985/wsman" if !@hyperv_endpoint && options[:hyperv_host]
140
145
  @hyperv_username = options[:hyperv_username]
141
146
  @hyperv_password = options[:hyperv_password]
142
- @hyperv_transport = options[:hyperv_transport] || :negotiate
147
+ @hyperv_realm = options[:hyperv_realm]
148
+ @hyperv_transport = options[:hyperv_transport] || (@hyperv_realm ? :kerberos : :negotiate)
149
+
150
+ Logging.logger['WinRM::HTTP::HttpNegotiate'].level = :error
143
151
  @logger = Logging.logger['hyper-v']
144
152
  if options[:hyperv_debug]
145
153
  logger.level = :debug
@@ -159,10 +167,15 @@ module Fog
159
167
  else
160
168
  run_wql('SELECT Name FROM Msvm_ComputerSystem WHERE Caption = "Hosting Computer System"') && true
161
169
  end
162
- rescue Fog::Hyperv::Errors::ServiceError
170
+ rescue => e
171
+ logger.debug "Validation failed with #{e.class}; #{e.message}"
163
172
  false
164
173
  end
165
174
 
175
+ def supports_multihop?
176
+ return [ :kerberos ].include? @hyperv_transport.to_s.downcase.to_sym
177
+ end
178
+
166
179
  def version
167
180
  @version ||= run_wql('SELECT Version FROM Win32_OperatingSystem', _namespace: 'root/cimv2/*')[:xml_fragment].first[:version] rescue \
168
181
  run_shell("$VMMS = if ([environment]::Is64BitProcess) { \"$($env:SystemRoot)\\System32\\vmms.exe\" } else { \"$($env:SystemRoot)\\Sysnative\\vmms.exe\" }\n(Get-Item $VMMS).VersionInfo.ProductVersion", _skip_json: true).stdout.strip
@@ -206,6 +219,7 @@ module Fog
206
219
  end
207
220
 
208
221
  def run_shell(command, options = {})
222
+ orig_opts = options.dup
209
223
  return_fields = options.delete :_return_fields
210
224
  return_fields = "| select #{Fog::Hyperv.camelize([return_fields].flatten).join ','}" if return_fields
211
225
  suffix = options.delete :_suffix
@@ -213,8 +227,28 @@ module Fog
213
227
  skip_json = options.delete :_skip_json
214
228
  skip_camelize = options.delete :_skip_camelize
215
229
  skip_uncamelize = options.delete :_skip_uncamelize
230
+ computer = options.delete(:_target_computer) || '.'
231
+ computers = [options.delete(:computer_name)].flatten.compact
216
232
  options = Fog::Hyperv.camelize(options) unless skip_camelize
217
233
 
234
+ if supports_multihop?
235
+ options[:computer_name] = computers
236
+ computer = '.'
237
+ elsif computers.length > 1 || (computers.length == 1 && !['.','localhost'].include?(computers.first.downcase))
238
+ logger.debug "Executing multi-query for #{computers}"
239
+ ret = []
240
+ computers.each do |c|
241
+ out = run_shell(command, orig_opts.merge(computer_name: nil, _target_computer: c))
242
+ if out.is_a? Array
243
+ ret += out
244
+ else
245
+ ret << out
246
+ end
247
+ end
248
+ return ret.first if ret.length == 1
249
+ return ret
250
+ end
251
+
218
252
  # commandline = "$Args = #{hash_to_optmap options}\n$Ret = #{command} @Args#{"\n$Ret #{return_fields} | ConvertTo-Json -Compress #{"-Depth #{json_depth}" if json_depth}" unless skip_json}"
219
253
  # puts " > #{commandline.split("\n").join "\n > "}" if @hyperv_debug
220
254
  args = options.reject { |k, v| v.nil? || v.is_a?(FalseClass) || k.to_s.start_with?('_') || (v.is_a?(String) && v.empty?) }.map do |k, v|
@@ -244,7 +278,7 @@ module Fog
244
278
  out.exitcode = -1
245
279
  end
246
280
  else
247
- @connection.shell(:powershell) do |shell|
281
+ connection(computer).shell(:powershell) do |shell|
248
282
  out = shell.run(commandline)
249
283
  end
250
284
  end
@@ -265,18 +299,43 @@ module Fog
265
299
  end
266
300
  end
267
301
 
268
- def connect
269
- # return require 'open3' if local?
302
+ def connect(endpoint = nil)
303
+ endpoint = @hyperv_endpoint unless endpoint
304
+ fqdn = URI.parse(endpoint).host
270
305
 
271
306
  require 'winrm'
272
- @connection = WinRM::Connection.new(
273
- endpoint: @hyperv_endpoint,
307
+ opts = {
308
+ endpoint: endpoint,
309
+ transport: @hyperv_transport,
274
310
  user: @hyperv_username,
275
311
  password: @hyperv_password,
276
- transport: @hyperv_transport
277
- )
278
- Logging.logger['WinRM::HTTP::HttpNegotiate'].level = :error
279
- @connection.logger.level = :error
312
+ realm: @hyperv_realm
313
+ }
314
+
315
+ logger.debug "Creating WinRM connection with #{opts.merge password: '<REDACTED>'}"
316
+ connection = WinRM::Connection.new opts
317
+ connection.logger.level = :error
318
+ @connections[fqdn] = connection
319
+
320
+ if endpoint == @hyperv_endpoint
321
+ @connection = connection
322
+ @connections['.'] = connection
323
+ @connections['localhost'] = connection
324
+ end
325
+ connection
326
+ end
327
+
328
+ def connection(host)
329
+ c = @connections.find { |k,_v| k.downcase.start_with?(host.downcase) }
330
+ return c[1] if c
331
+
332
+ # TODO: Support non-standard endpoints for additional hosts
333
+ unless host.include? '.'
334
+ host = "#{host}.#{URI.parse(@hyperv_endpoint).host.split('.').drop(1).join('.')}"
335
+ end
336
+ endpoint = "http://#{host}:5985/wsman"
337
+
338
+ connect(endpoint)
280
339
  end
281
340
  end
282
341
 
@@ -8,17 +8,37 @@ module Fog
8
8
  super
9
9
  end
10
10
 
11
+ def ensure_value_getter
12
+ return if model.methods.include?("#{name}_values".to_sym)
13
+ model.class_eval <<-EOS, __FILE__, __LINE__
14
+ def #{name}_values
15
+ #{values}.freeze
16
+ end
17
+ EOS
18
+ end
19
+
11
20
  def create_setter
21
+ ensure_value_getter
12
22
  model.class_eval <<-EOS, __FILE__, __LINE__
13
23
  def #{name}=(new_#{name})
24
+ _values = #{name}_values
25
+ # FIXME: Prepare a key comparison array in advance
14
26
  if new_#{name}.is_a?(Fixnum)
15
- raise Fog::Hyperv::Errors::ServiceError, "\#{new_#{name}} is not in the range (0..#{values.length - 1})" unless new_#{name} >= 0 && new_#{name} < #{values.length}
16
- attributes[:#{name}] = #{values}[new_#{name}]
27
+ if _values.class.to_s == 'Array' # TODO: Better way to do class comparison in generated code
28
+ puts "\#{_values} (\#{_values.class}) Is array"
29
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_#{name}} is not in the range (0..\#{_values.length - 1})" unless new_#{name} >= 0 && new_#{name} < _values.length
30
+ else
31
+ puts "\#{_values} (\#{_values.class}) Is not array"
32
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_#{name}} is not one of \#{_values.is_a?(Hash) ? _values.keys : _values})" unless (_values.is_a?(Hash) ? _values.keys : _values).include? new_#{name}
33
+ end
34
+
35
+ attributes[:#{name}] = _values[new_#{name}]
17
36
  elsif new_#{name}.nil?
18
37
  attributes[:#{name}] = nil
19
38
  else
39
+ puts "Is string"
20
40
  new_#{name} = new_#{name}.to_s.to_sym unless new_#{name}.is_a? String
21
- raise Fog::Hyperv::Errors::ServiceError, "\#{new_#{name}} is not one of #{values.is_a?(Hash) ? values.values : values})" unless #{(values.is_a?(Hash) ? values.values : values)}.include? new_#{name}
41
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_#{name}} is not one of \#{_values.is_a?(Hash) ? _values.keys : _values})" unless (_values.is_a?(Hash) ? _values.keys : _values).include? new_#{name}
22
42
  attributes[:#{name}] = new_#{name}
23
43
  end
24
44
  end
@@ -26,23 +46,21 @@ module Fog
26
46
  end
27
47
 
28
48
  def create_getter
49
+ ensure_value_getter
29
50
  model.class_eval <<-EOS, __FILE__, __LINE__
30
51
  def #{name}_num
52
+ _values = #{name}_values
31
53
  return nil if self.#{name}.nil?
32
54
  if self.#{name}.is_a?(Fixnum)
33
55
  self.#{name}
34
56
  else
35
- if #{values}.is_a?(Hash)
36
- #{values}.key(self.#{name})
57
+ if _values.is_a?(Hash)
58
+ _values.key(self.#{name})
37
59
  else
38
- #{values}.index(self.#{name})
60
+ _values.index(self.#{name})
39
61
  end
40
62
  end
41
63
  end
42
-
43
- def #{name}_values
44
- #{values}.freeze
45
- end
46
64
  EOS
47
65
  super
48
66
  end
@@ -10,6 +10,14 @@ module Fog
10
10
  # TODO? Enum values; :CD, :IDE, :LegacyNetworkAdapter, :Floppy (, :VHD, :NetworkAdapter)
11
11
  attribute :startup_order, type: :array
12
12
  attribute :vm_name, type: :string
13
+
14
+ attr_reader :computer, :vm
15
+
16
+ def initialize(args = {})
17
+ super
18
+ @computer = args.delete :computer
19
+ @vm = args.delete :vm
20
+ end
13
21
 
14
22
  def save
15
23
  requires :computer_name, :vm_name
@@ -8,16 +8,19 @@ module Fog
8
8
  attribute :domain, type: :string
9
9
  attribute :name, type: :string
10
10
 
11
+ def initialize(attrs = {})
12
+ super
13
+
14
+ @collections = {}
15
+ self.class.ensure_collections!
16
+ end
17
+
11
18
  def nodes
12
19
  @nodes ||= [service.get_cluster_node(cluster: name, _return_fields: [:description, :name, :node_name])].flatten
13
20
  end
14
21
 
15
22
  def hosts
16
- @hosts ||= service.hosts computer_name: nodes.map { |n| n[:name] }
17
- end
18
-
19
- def servers
20
- @servers ||= service.servers cluster: self
23
+ @hosts ||= nodes.map { |n| service.hosts.get(n[:name]) }
21
24
  end
22
25
 
23
26
  def reload
@@ -33,6 +36,23 @@ module Fog
33
36
  merge_attributes(data.attributes)
34
37
  self
35
38
  end
39
+
40
+ def self.ensure_collections!
41
+ return if @collections
42
+ @collections = true
43
+
44
+ Fog::Compute::Hyperv.collections.each do |coll|
45
+ # Don't recurse on hosts
46
+ next if coll == :hosts
47
+ coll_name = coll.to_s.split('_').map(&:capitalize).join
48
+ klass = Fog::Compute::Hyperv.const_get(coll_name)
49
+ next if klass.requires?(:vm)
50
+
51
+ define_method coll do
52
+ @collections[coll] ||= service.send(coll, cluster: self)
53
+ end
54
+ end
55
+ end
36
56
  end
37
57
  end
38
58
  end
@@ -5,6 +5,10 @@ module Fog
5
5
  model Fog::Compute::Hyperv::Cluster
6
6
 
7
7
  get_method :get_cluster
8
+
9
+ def get(name, filters = {})
10
+ super(filters.merge(name: name))
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -5,10 +5,10 @@ module Fog
5
5
  identity :id
6
6
 
7
7
  attribute :computer_name
8
- attribute :debugger_mode, type: :enum, values: [ :On, :Off ]
8
+ attribute :debugger_mode, type: :enum, values: %i[On Off]
9
9
  attribute :name
10
10
  attribute :path
11
-
11
+
12
12
  def save
13
13
  raise Fog::Errors::NotImplemented
14
14
  end
@@ -11,36 +11,65 @@ module Fog
11
11
  attribute :pool_name
12
12
  attribute :controller_location
13
13
  attribute :controller_number
14
- attribute :controller_type, type: :enum, values: [ :IDE, :SCSI ]
15
- attribute :dvd_media_type, type: :enum, values: [ :None, :ISO, :Passthrough ]
14
+ attribute :controller_type, type: :enum, values: %i[IDE SCSI]
15
+ attribute :dvd_media_type, type: :enum, values: %i[None ISO Passthrough]
16
16
  attribute :vm_id
17
17
  attribute :vm_name
18
18
  # TODO? VM Snapshots?
19
19
  #
20
- attr_accessor :to_controller_number, :to_controller_location
21
20
 
22
21
  def save
23
22
  requires :computer_name, :vm_name
24
23
 
25
- data = service.set_vm_dvd_drive(
26
- computer_name: computer_name,
27
- vm_name: vm_name,
28
- passthru: true,
24
+ data = \
25
+ if persisted?
26
+ service.set_vm_dvd_drive(
27
+ computer_name: old.computer_name,
28
+ vm_name: old.vm_name,
29
+ controller_number: old.controller_number,
30
+ controller_location: old.controller_location,
31
+ passthru: true,
29
32
 
30
- controller_number: controller_number,
31
- controller_location: controller_location,
32
- resource_pool_name: pool_name,
33
- path: path || '$null',
34
- to_controller_number: to_controller_number,
35
- to_controller_location: to_controller_location,
33
+ resource_pool_name: changed!(:pool_name),
34
+ path: changed?(:path) && (path || '$null'),
35
+ to_controller_number: changed!(:controller_number),
36
+ to_controller_location: changed!(:controller_location),
37
+
38
+ _return_fields: self.class.attributes,
39
+ _json_depth: 1
40
+ )
41
+ else
42
+ service.add_vm_dvd_drive(
43
+ computer_name: computer_name,
44
+ vm_name: vm_name,
45
+ passthru: true,
46
+
47
+ controller_number: controller_number,
48
+ controller_location: controller_location,
49
+ path: path,
50
+ resource_pool_name: pool_name,
51
+
52
+ _return_fields: self.class.attributes,
53
+ _json_depth: 1
54
+ )
55
+ end
36
56
 
37
- _return_fields: self.class.attributes,
38
- _json_depth: 1
39
- )
40
57
  merge_attributes(data)
58
+ @old = dup
41
59
  self
42
60
  end
43
61
 
62
+ def destroy
63
+ requires :computer_name, :vm_name, :controller_number, :controller_location
64
+
65
+ service.remove_vm_dvd_drive(
66
+ computer_name: computer_name,
67
+ vm_name: vm_name,
68
+ controller_number: controller_number,
69
+ controller_location: controller_location
70
+ )
71
+ end
72
+
44
73
  def reload
45
74
  requires :computer_name, :vm_name
46
75
 
@@ -54,6 +83,7 @@ module Fog
54
83
  _json_depth: 1
55
84
  )
56
85
  merge_attributes(data.attributes)
86
+ @old = data
57
87
  self
58
88
  end
59
89
  end
@@ -44,6 +44,7 @@ module Fog
44
44
  _return_fields: self.class.attributes
45
45
  )
46
46
  merge_attributes(data)
47
+ @old = data
47
48
  self
48
49
  end
49
50
  end
@@ -6,7 +6,7 @@ module Fog
6
6
 
7
7
  attribute :computer_name
8
8
  attribute :disk
9
- attribute :is_deleted
9
+ # attribute :is_deleted
10
10
  attribute :name
11
11
  attribute :path
12
12
  attribute :pool_name
@@ -16,21 +16,25 @@ module Fog
16
16
  #
17
17
 
18
18
  def save
19
+ raise Fog::Hyperv::Errors::ServiceError, "Can't create new floppy drives" unless persisted?
20
+
19
21
  requires :computer_name, :vm_name
20
22
 
21
- data = service.set_vm_floppy_disk_drive(
22
- computer_name: computer_name,
23
- vm_name: vm_name,
24
- passthru: true,
23
+ data = \
24
+ service.set_vm_floppy_disk_drive(
25
+ computer_name: old.computer_name,
26
+ vm_name: old.vm_name,
27
+ passthru: true,
25
28
 
26
- resource_pool_name: pool_name,
27
- path: path,
29
+ resource_pool_name: changed!(:pool_name),
30
+ path: changed?(:path) && (path || '$null'),
28
31
 
29
- _return_fields: self.class.attributes,
30
- _json_depth: 1
31
- )
32
+ _return_fields: self.class.attributes,
33
+ _json_depth: 1
34
+ )
32
35
 
33
36
  merge_attributes(data)
37
+ @old = dup
34
38
  self
35
39
  end
36
40
 
@@ -40,6 +44,7 @@ module Fog
40
44
  vm_name: vm_name
41
45
  )
42
46
  merge_attributes(data.attributes)
47
+ @old = data
43
48
  self
44
49
  end
45
50
  end
@@ -6,12 +6,12 @@ module Fog
6
6
 
7
7
  attribute :computer_name
8
8
  attribute :controller_location
9
- attribute :controller_number
10
- attribute :controller_type, type: :enum, values: [ :IDE, :SCSI ]
9
+ attribute :controller_number, type: :integer
10
+ attribute :controller_type, type: :enum, values: %i[IDE SCSI]
11
11
  attribute :disk
12
12
  # attribute :is_deleted
13
- attribute :maximum_iops
14
- attribute :minimum_iops
13
+ attribute :maximum_iops, type: :integer
14
+ attribute :minimum_iops, type: :integer
15
15
  attribute :name
16
16
  attribute :path
17
17
  attribute :pool_name
@@ -22,7 +22,7 @@ module Fog
22
22
 
23
23
  def vhd
24
24
  return nil unless path && computer_name
25
- @vhd ||= Fog::Compute::Hyperv::Vhd.new(service.get_vhd(computer_name: computer_name, path: path).merge(service: service))
25
+ @vhd ||= service.vhds.get(path, computer_name: computer_name)
26
26
  end
27
27
 
28
28
  def size_bytes
@@ -43,24 +43,24 @@ module Fog
43
43
  controller_location: old.controller_location,
44
44
  controller_number: old.controller_number,
45
45
  controller_type: old.controller_type,
46
+ passthru: true,
46
47
 
47
48
  disk_number: changed?(:disk) && disk && disk.number,
48
- maximum_iops: changed?(:maximum_iops) && maximum_iops,
49
- minimum_iops: changed?(:minimum_iops) && minimum_iops,
50
- path: changed?(:path) && path,
51
- resource_pool_name: changed?(:pool_name) && pool_name,
52
- support_persistent_reservations: changed?(:support_persistent_reservations) && support_persistent_reservations,
53
- to_controller_location: changed?(:controller_location) && controller_location,
54
- to_controller_number: changed?(:controller_number) && controller_number,
55
- to_controller_type: changed?(:controller_type) && controller_type,
49
+ maximum_iops: changed!(:maximum_iops),
50
+ minimum_iops: changed!(:minimum_iops),
51
+ path: changed!(:path),
52
+ resource_pool_name: changed!(:pool_name),
53
+ support_persistent_reservations: changed!(:support_persistent_reservations),
54
+ to_controller_location: changed!(:controller_location),
55
+ to_controller_number: changed!(:controller_number),
56
+ to_controller_type: changed!(:controller_type),
56
57
 
57
- passthru: true,
58
58
  _return_fields: self.class.attributes,
59
59
  _json_depth: 1
60
60
  )
61
61
  @vhd = nil if changed?(:path)
62
62
  else
63
- possible = %i(computer_name controller_location controller_number controller_type path vm_name).freeze
63
+ possible = %i[computer_name controller_location controller_number controller_type path vm_name].freeze
64
64
  data = service.add_vm_hard_disk_drive(
65
65
  attributes.select { |k, _v| possible.include? k }.merge(
66
66
  disk_number: disk && disk.number,
@@ -29,7 +29,7 @@ module Fog
29
29
  Fog::Compute::Hyperv.collections.each do |coll|
30
30
  coll_name = coll.to_s.split('_').map(&:capitalize).join
31
31
  klass = Fog::Compute::Hyperv.const_get(coll_name)
32
- next if klass.requires? :vm
32
+ next if klass.requires?(:vm)
33
33
 
34
34
  define_method coll do
35
35
  @collections[coll] ||= service.send(coll, computer: self)
@@ -83,7 +83,7 @@ module Fog
83
83
  passthru: true,
84
84
 
85
85
  dynamic_mac_address: changed?(:dynamic_mac_address_enabled) && dynamic_mac_address_enabled,
86
- static_mac_address: (changed?(:mac_address) || changed?(:dynamic_mac_address_enabled)) && !dynamic_mac_address_enabled && mac_address,
86
+ static_mac_address: changed!(:mac_address) || ((changed!(:dynamic_mac_address_enabled) == false) && mac_address),
87
87
 
88
88
  _return_fields: self.class.attributes,
89
89
  _json_depth: 1
@@ -134,6 +134,7 @@ module Fog
134
134
  vm_name: vm_name
135
135
  )
136
136
  merge_attributes(data.attributes)
137
+ @old = data
137
138
  self
138
139
  end
139
140
  end
@@ -45,6 +45,7 @@ module Fog
45
45
  attribute :com_port2
46
46
  attribute :dynamic_memory_enabled, type: :boolean, default: false
47
47
  attribute :generation, type: :integer, default: 1 # 1 => bios, 2 => uefi
48
+ attribute :is_clustered, type: :boolean, default: false
48
49
  attribute :state, type: :enum, values: VM_STATUS_ENUM_VALUES
49
50
  attribute :status, type: :string
50
51
  attribute :memory_assigned, type: :integer
@@ -59,6 +60,8 @@ module Fog
59
60
  :hard_drives,
60
61
  :floppy_drive
61
62
 
63
+ attr_accessor :cluster_name
64
+
62
65
  %i(network_adapters dvd_drives floppy_drives hard_drives vhds).each do |attr|
63
66
  define_method attr do
64
67
  if persisted?
@@ -75,6 +78,13 @@ module Fog
75
78
  end
76
79
  end
77
80
 
81
+ def initialize(attrs = {})
82
+ super
83
+
84
+ @cluster = attrs.delete :cluster
85
+ @computer = attrs.delete :computer
86
+ end
87
+
78
88
  def bios
79
89
  @bios ||= begin
80
90
  if generation == 1
@@ -11,36 +11,42 @@ module Fog
11
11
  attribute :name
12
12
  attribute :net_adapter_interface_description
13
13
  attribute :notes
14
- attribute :switch_type, type: :enum, values: [ :Private, :Internal, :External ]
14
+ attribute :switch_type, type: :enum, values: %i[Private Internal External]
15
15
 
16
16
  def save
17
17
  requires :name
18
18
 
19
- data = if persisted?
20
- service.set_vm_switch(
21
- computer_name: computer_name,
22
- default_flow_minimum_bandwidth_absolute: default_flow_minimum_bandwidth_absolute,
23
- default_flow_minimum_bandwidth_weight: default_flow_minimum_bandwidth_weight,
24
- name: name,
25
- net_adapter_interface_description: net_adapter_interface_description,
26
- notes: notes,
27
- switch_type: !net_adapter_interface_description && switch_type,
28
- passthru: true,
29
- _return_fields: self.class.attributes,
30
- _json_depth: 1
31
- )
32
- else
33
- service.new_vm_switch(
34
- computer_name: computer_name,
35
- name: name,
36
- net_adapter_interface_description: net_adapter_interface_description,
37
- notes: notes,
38
- switch_type: !net_adapter_interface_description && switch_type,
39
- _return_fields: self.class.attributes,
40
- _json_depth: 1
41
- )
42
- end
19
+ data = \
20
+ if persisted?
21
+ service.set_vm_switch(
22
+ computer_name: old.computer_name,
23
+ name: old.name,
24
+ net_adapter_interface_description: old.net_adapter_interface_description,
25
+ switch_type: !old.net_adapter_interface_description && old.switch_type,
26
+ passthru: true,
27
+
28
+ default_flow_minimum_bandwidth_absolute: changed!(default_flow_minimum_bandwidth_absolute),
29
+ default_flow_minimum_bandwidth_weight: changed!(default_flow_minimum_bandwidth_weight),
30
+ notes: changed!(notes),
31
+
32
+ _return_fields: self.class.attributes,
33
+ _json_depth: 1
34
+ )
35
+ else
36
+ service.new_vm_switch(
37
+ computer_name: computer_name,
38
+ name: name,
39
+ net_adapter_interface_description: net_adapter_interface_description,
40
+ notes: notes,
41
+ switch_type: !net_adapter_interface_description && switch_type,
42
+
43
+ _return_fields: self.class.attributes,
44
+ _json_depth: 1
45
+ )
46
+ end
47
+
43
48
  merge_attributes(data)
49
+ @old = dup
44
50
  self
45
51
  end
46
52
 
@@ -50,6 +56,7 @@ module Fog
50
56
  computer_name: computer_name
51
57
  )
52
58
  merge_attributes(data.attributes)
59
+ @old = data
53
60
  self
54
61
  end
55
62
  end
@@ -14,8 +14,8 @@ module Fog
14
14
  attribute :path, type: :string, default: 'New Disk'
15
15
  attribute :pool_name
16
16
  attribute :size, type: :integer, default: 343_597_383_68
17
- attribute :vhd_format, type: :enum, values: [ :Unknown, nil, :VHD, :VHDX, :VHDSet ]
18
- attribute :vhd_type, type: :enum, values: [ :Unknown, nil, :Fixed, :Dynamic, :Differencing ]
17
+ attribute :vhd_format, type: :enum, values: [:Unknown, nil, :VHD, :VHDX, :VHDSet]
18
+ attribute :vhd_type, type: :enum, values: [:Unknown, nil, :Fixed, :Dynamic, :Differencing]
19
19
  # TODO? VM Snapshots?
20
20
  #
21
21
 
@@ -35,7 +35,7 @@ module Fog
35
35
  end
36
36
 
37
37
  def unc_path
38
- "\\\\#{computer_name || '.'}\\#{real_path.gsub ':', '$'}"
38
+ "\\\\#{computer_name || '.'}\\#{real_path.tr ':', '$'}"
39
39
  end
40
40
 
41
41
  def host
@@ -84,6 +84,7 @@ module Fog
84
84
  disk_number: disk
85
85
  )
86
86
  merge_attributes(data.attributes)
87
+ @old = data
87
88
  self
88
89
  end
89
90
 
@@ -92,7 +93,7 @@ module Fog
92
93
 
93
94
  service.remove_item(
94
95
  path: unc_path
95
- ) if path
96
+ )
96
97
  end
97
98
  end
98
99
  end
@@ -0,0 +1,12 @@
1
+ module Fog
2
+ module Compute
3
+ class Hyperv
4
+ class Real
5
+ def add_vm_dvd_disk_drive(options = {})
6
+ requires options, :vm_name
7
+ run_shell('Add-VMDvdDrive', options)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Fog
2
+ module Compute
3
+ class Hyperv
4
+ class Real
5
+ def remove_vm_dvd_drive(options = {})
6
+ requires options, :vm_name, :controller_number, :controller_location
7
+ run_shell('Remove-VMDvdDrive', options.merge(_skip_json: true)).exitcode.zero?
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module Hyperv
3
- VERSION = '0.0.3'.freeze
3
+ VERSION = '0.0.4'.freeze
4
4
  end
5
5
  end
@@ -19,6 +19,9 @@ module Fog
19
19
  end
20
20
 
21
21
  def parent
22
+ return @vm if @vm
23
+ return @computer if @computer
24
+ return @cluster if @cluster
22
25
  return nil unless collection
23
26
  return collection.vm if collection.attributes.include? :vm
24
27
  return collection.computer if collection.attributes.include? :computer
@@ -29,6 +32,24 @@ module Fog
29
32
  end
30
33
  end
31
34
 
35
+ def vm
36
+ if respond_to?(:vm_name) && vm_name
37
+ @vm ||= service.servers.get vm_name
38
+ end
39
+ end
40
+
41
+ def computer
42
+ if respond_to?(:computer_name) && computer_name
43
+ @computer ||= service.hosts.get computer_name
44
+ end
45
+ end
46
+
47
+ def cluster
48
+ if respond_to?(:cluster_name) && cluster_name
49
+ @cluster ||= service.clusters.get cluster_name
50
+ end
51
+ end
52
+
32
53
  private
33
54
 
34
55
  def logger
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog-hyperv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Olofsson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-30 00:00:00.000000000 Z
11
+ date: 2017-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fog-core
@@ -120,6 +120,7 @@ files:
120
120
  - lib/fog/hyperv/models/compute/switches.rb
121
121
  - lib/fog/hyperv/models/compute/vhd.rb
122
122
  - lib/fog/hyperv/models/compute/vhds.rb
123
+ - lib/fog/hyperv/requests/compute/add_vm_dvd_drive.rb
123
124
  - lib/fog/hyperv/requests/compute/add_vm_hard_disk_drive.rb
124
125
  - lib/fog/hyperv/requests/compute/add_vm_network_adapter.rb
125
126
  - lib/fog/hyperv/requests/compute/connect_vm_network_adapter.rb
@@ -155,6 +156,7 @@ files:
155
156
  - lib/fog/hyperv/requests/compute/new_vm_switch.rb
156
157
  - lib/fog/hyperv/requests/compute/remove_item.rb
157
158
  - lib/fog/hyperv/requests/compute/remove_vm.rb
159
+ - lib/fog/hyperv/requests/compute/remove_vm_dvd_drive.rb
158
160
  - lib/fog/hyperv/requests/compute/remove_vm_hard_disk_drive.rb
159
161
  - lib/fog/hyperv/requests/compute/remove_vm_network_adapter.rb
160
162
  - lib/fog/hyperv/requests/compute/restart_vm.rb
@@ -191,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
193
  version: '0'
192
194
  requirements: []
193
195
  rubyforge_project:
194
- rubygems_version: 2.6.12
196
+ rubygems_version: 2.6.14
195
197
  signing_key:
196
198
  specification_version: 4
197
199
  summary: Module for the `fog` gem to support Microsoft Hyper-V.