fog-hyperv 0.0.9 → 0.1.1

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.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -2
  3. data/lib/fog/bin/hyperv.rb +6 -4
  4. data/lib/fog/hyperv/collection.rb +89 -0
  5. data/lib/fog/hyperv/compute/models/bios.rb +70 -0
  6. data/lib/fog/hyperv/compute/models/cluster.rb +50 -0
  7. data/lib/fog/hyperv/compute/models/clusters.rb +21 -0
  8. data/lib/fog/hyperv/compute/models/com_port.rb +78 -0
  9. data/lib/fog/hyperv/compute/models/com_ports.rb +29 -0
  10. data/lib/fog/hyperv/compute/models/dvd_drive.rb +126 -0
  11. data/lib/fog/hyperv/compute/models/dvd_drives.rb +29 -0
  12. data/lib/fog/hyperv/compute/models/firmware.rb +78 -0
  13. data/lib/fog/hyperv/compute/models/floppy_drive.rb +64 -0
  14. data/lib/fog/hyperv/compute/models/floppy_drives.rb +18 -0
  15. data/lib/fog/hyperv/compute/models/hard_drive.rb +183 -0
  16. data/lib/fog/hyperv/compute/models/hard_drives.rb +28 -0
  17. data/lib/fog/hyperv/compute/models/host.rb +63 -0
  18. data/lib/fog/hyperv/compute/models/hosts.rb +13 -0
  19. data/lib/fog/hyperv/compute/models/network_adapter.rb +368 -0
  20. data/lib/fog/hyperv/compute/models/network_adapter_vlan.rb +172 -0
  21. data/lib/fog/hyperv/compute/models/network_adapters.rb +32 -0
  22. data/lib/fog/hyperv/compute/models/security.rb +121 -0
  23. data/lib/fog/hyperv/compute/models/server.rb +466 -0
  24. data/lib/fog/hyperv/compute/models/servers.rb +18 -0
  25. data/lib/fog/hyperv/compute/models/switch.rb +117 -0
  26. data/lib/fog/hyperv/compute/models/switches.rb +20 -0
  27. data/lib/fog/hyperv/compute/models/vhd.rb +210 -0
  28. data/lib/fog/hyperv/compute/models/vhds.rb +28 -0
  29. data/lib/fog/hyperv/compute/requests/add_vm_dvd_drive.rb +15 -0
  30. data/lib/fog/hyperv/compute/requests/add_vm_hard_disk_drive.rb +15 -0
  31. data/lib/fog/hyperv/compute/requests/add_vm_network_adapter.rb +24 -0
  32. data/lib/fog/hyperv/compute/requests/connect_vm_network_adapter.rb +41 -0
  33. data/lib/fog/hyperv/compute/requests/disable_vm_tpm.rb +16 -0
  34. data/lib/fog/hyperv/compute/requests/disconnect_vm_network_adapter.rb +29 -0
  35. data/lib/fog/hyperv/compute/requests/enable_vm_tpm.rb +16 -0
  36. data/lib/fog/hyperv/compute/requests/get_cluster.rb +11 -0
  37. data/lib/fog/hyperv/compute/requests/get_cluster_node.rb +22 -0
  38. data/lib/fog/hyperv/compute/requests/get_vhd.rb +32 -0
  39. data/lib/fog/hyperv/compute/requests/get_vm.rb +18 -0
  40. data/lib/fog/hyperv/compute/requests/get_vm_bios.rb +21 -0
  41. data/lib/fog/hyperv/compute/requests/get_vm_com_port.rb +17 -0
  42. data/lib/fog/hyperv/compute/requests/get_vm_dvd_drive.rb +25 -0
  43. data/lib/fog/hyperv/compute/requests/get_vm_firmware.rb +21 -0
  44. data/lib/fog/hyperv/compute/requests/get_vm_floppy_disk_drive.rb +16 -0
  45. data/lib/fog/hyperv/compute/requests/get_vm_group.rb +20 -0
  46. data/lib/fog/hyperv/compute/requests/get_vm_hard_disk_drive.rb +24 -0
  47. data/lib/fog/hyperv/compute/requests/get_vm_host.rb +9 -0
  48. data/lib/fog/hyperv/compute/requests/get_vm_host_cluster.rb +21 -0
  49. data/lib/fog/hyperv/compute/requests/get_vm_host_sbt.rb +10 -0
  50. data/lib/fog/hyperv/compute/requests/get_vm_key_protector.rb +16 -0
  51. data/lib/fog/hyperv/compute/requests/get_vm_network_adapter.rb +41 -0
  52. data/lib/fog/hyperv/compute/requests/get_vm_network_adapter_vlan.rb +41 -0
  53. data/lib/fog/hyperv/compute/requests/get_vm_security.rb +15 -0
  54. data/lib/fog/hyperv/compute/requests/get_vm_switch.rb +10 -0
  55. data/lib/fog/hyperv/compute/requests/mock_files/get_vm.json +4 -0
  56. data/lib/fog/hyperv/compute/requests/new_vhd.rb +9 -0
  57. data/lib/fog/hyperv/compute/requests/new_vm.rb +12 -0
  58. data/lib/fog/hyperv/compute/requests/new_vm_switch.rb +11 -0
  59. data/lib/fog/hyperv/compute/requests/optimize_vhd.rb +9 -0
  60. data/lib/fog/hyperv/compute/requests/remove_item.rb +10 -0
  61. data/lib/fog/hyperv/compute/requests/remove_vm.rb +16 -0
  62. data/lib/fog/hyperv/compute/requests/remove_vm_dvd_drive.rb +17 -0
  63. data/lib/fog/hyperv/compute/requests/remove_vm_hard_disk_drive.rb +17 -0
  64. data/lib/fog/hyperv/compute/requests/remove_vm_network_adapter.rb +29 -0
  65. data/lib/fog/hyperv/compute/requests/remove_vm_switch.rb +9 -0
  66. data/lib/fog/hyperv/compute/requests/rename_vm.rb +16 -0
  67. data/lib/fog/hyperv/compute/requests/rename_vm_network_adapter.rb +25 -0
  68. data/lib/fog/hyperv/compute/requests/rename_vm_switch.rb +16 -0
  69. data/lib/fog/hyperv/compute/requests/resize_vhd.rb +16 -0
  70. data/lib/fog/hyperv/compute/requests/restart_vm.rb +22 -0
  71. data/lib/fog/hyperv/compute/requests/resume_vm.rb +22 -0
  72. data/lib/fog/hyperv/compute/requests/save_vm.rb +22 -0
  73. data/lib/fog/hyperv/compute/requests/set_vm.rb +15 -0
  74. data/lib/fog/hyperv/compute/requests/set_vm_bios.rb +15 -0
  75. data/lib/fog/hyperv/compute/requests/set_vm_com_port.rb +16 -0
  76. data/lib/fog/hyperv/compute/requests/set_vm_dvd_drive.rb +16 -0
  77. data/lib/fog/hyperv/compute/requests/set_vm_firmware.rb +15 -0
  78. data/lib/fog/hyperv/compute/requests/set_vm_floppy_disk_drive.rb +16 -0
  79. data/lib/fog/hyperv/compute/requests/set_vm_hard_disk_drive.rb +16 -0
  80. data/lib/fog/hyperv/compute/requests/set_vm_key_protector.rb +15 -0
  81. data/lib/fog/hyperv/compute/requests/set_vm_network_adapter.rb +25 -0
  82. data/lib/fog/hyperv/compute/requests/set_vm_network_adapter_vlan.rb +25 -0
  83. data/lib/fog/hyperv/compute/requests/set_vm_security.rb +17 -0
  84. data/lib/fog/hyperv/compute/requests/set_vm_switch.rb +9 -0
  85. data/lib/fog/hyperv/compute/requests/start_vm.rb +22 -0
  86. data/lib/fog/hyperv/compute/requests/stop_vm.rb +22 -0
  87. data/lib/fog/hyperv/compute/requests/suspend_vm.rb +22 -0
  88. data/lib/fog/hyperv/compute/requests/update_vm.rb +22 -0
  89. data/lib/fog/hyperv/compute.rb +206 -387
  90. data/lib/fog/hyperv/constants.rb +24 -0
  91. data/lib/fog/hyperv/fog_extensions/associations/collection.rb +11 -0
  92. data/lib/fog/hyperv/fog_extensions/attributes/datetime.rb +28 -0
  93. data/lib/fog/hyperv/fog_extensions/attributes/enum.rb +139 -0
  94. data/lib/fog/hyperv/fog_extensions/attributes/enumarray.rb +149 -0
  95. data/lib/fog/hyperv/fog_extensions/attributes/timespan.rb +27 -0
  96. data/lib/fog/hyperv/model.rb +142 -0
  97. data/lib/fog/hyperv/utils/powershell.rb +88 -0
  98. data/lib/fog/hyperv/utils/winrm.rb +233 -0
  99. data/lib/fog/hyperv/version.rb +4 -1
  100. data/lib/fog/hyperv.rb +53 -44
  101. metadata +187 -105
  102. data/.gitignore +0 -10
  103. data/.travis.yml +0 -11
  104. data/CHANGELOG.md +0 -52
  105. data/Gemfile +0 -4
  106. data/Rakefile +0 -10
  107. data/fog-hyperv.gemspec +0 -25
  108. data/lib/fog/collection.rb +0 -152
  109. data/lib/fog/hyperv/fog_extensions/enum.rb +0 -85
  110. data/lib/fog/hyperv/models/compute/bios.rb +0 -61
  111. data/lib/fog/hyperv/models/compute/cluster.rb +0 -64
  112. data/lib/fog/hyperv/models/compute/clusters.rb +0 -15
  113. data/lib/fog/hyperv/models/compute/com_port.rb +0 -22
  114. data/lib/fog/hyperv/models/compute/dvd_drive.rb +0 -92
  115. data/lib/fog/hyperv/models/compute/dvd_drives.rb +0 -12
  116. data/lib/fog/hyperv/models/compute/firmware.rb +0 -53
  117. data/lib/fog/hyperv/models/compute/floppy_drive.rb +0 -53
  118. data/lib/fog/hyperv/models/compute/floppy_drives.rb +0 -12
  119. data/lib/fog/hyperv/models/compute/hard_drive.rb +0 -110
  120. data/lib/fog/hyperv/models/compute/hard_drives.rb +0 -11
  121. data/lib/fog/hyperv/models/compute/host.rb +0 -45
  122. data/lib/fog/hyperv/models/compute/hosts.rb +0 -15
  123. data/lib/fog/hyperv/models/compute/network_adapter.rb +0 -145
  124. data/lib/fog/hyperv/models/compute/network_adapters.rb +0 -19
  125. data/lib/fog/hyperv/models/compute/server.rb +0 -220
  126. data/lib/fog/hyperv/models/compute/servers.rb +0 -21
  127. data/lib/fog/hyperv/models/compute/switch.rb +0 -65
  128. data/lib/fog/hyperv/models/compute/switches.rb +0 -15
  129. data/lib/fog/hyperv/models/compute/vhd.rb +0 -101
  130. data/lib/fog/hyperv/models/compute/vhds.rb +0 -16
  131. data/lib/fog/hyperv/requests/compute/add_vm_dvd_drive.rb +0 -12
  132. data/lib/fog/hyperv/requests/compute/add_vm_hard_disk_drive.rb +0 -12
  133. data/lib/fog/hyperv/requests/compute/add_vm_network_adapter.rb +0 -12
  134. data/lib/fog/hyperv/requests/compute/connect_vm_network_adapter.rb +0 -12
  135. data/lib/fog/hyperv/requests/compute/disconnect_vm_network_adapter.rb +0 -12
  136. data/lib/fog/hyperv/requests/compute/get_cluster.rb +0 -11
  137. data/lib/fog/hyperv/requests/compute/get_cluster_node.rb +0 -19
  138. data/lib/fog/hyperv/requests/compute/get_vhd.rb +0 -34
  139. data/lib/fog/hyperv/requests/compute/get_vm.rb +0 -20
  140. data/lib/fog/hyperv/requests/compute/get_vm_bios.rb +0 -21
  141. data/lib/fog/hyperv/requests/compute/get_vm_dvd_drive.rb +0 -20
  142. data/lib/fog/hyperv/requests/compute/get_vm_firmware.rb +0 -19
  143. data/lib/fog/hyperv/requests/compute/get_vm_floppy_disk_drive.rb +0 -20
  144. data/lib/fog/hyperv/requests/compute/get_vm_group.rb +0 -23
  145. data/lib/fog/hyperv/requests/compute/get_vm_hard_disk_drive.rb +0 -20
  146. data/lib/fog/hyperv/requests/compute/get_vm_host.rb +0 -12
  147. data/lib/fog/hyperv/requests/compute/get_vm_host_cluster.rb +0 -25
  148. data/lib/fog/hyperv/requests/compute/get_vm_network_adapter.rb +0 -27
  149. data/lib/fog/hyperv/requests/compute/get_vm_switch.rb +0 -27
  150. data/lib/fog/hyperv/requests/compute/mock_files/get_vm.json +0 -1
  151. data/lib/fog/hyperv/requests/compute/new_vhd.rb +0 -12
  152. data/lib/fog/hyperv/requests/compute/new_vm.rb +0 -15
  153. data/lib/fog/hyperv/requests/compute/new_vm_switch.rb +0 -13
  154. data/lib/fog/hyperv/requests/compute/remove_item.rb +0 -13
  155. data/lib/fog/hyperv/requests/compute/remove_vm.rb +0 -15
  156. data/lib/fog/hyperv/requests/compute/remove_vm_dvd_drive.rb +0 -12
  157. data/lib/fog/hyperv/requests/compute/remove_vm_hard_disk_drive.rb +0 -12
  158. data/lib/fog/hyperv/requests/compute/remove_vm_network_adapter.rb +0 -12
  159. data/lib/fog/hyperv/requests/compute/restart_vm.rb +0 -15
  160. data/lib/fog/hyperv/requests/compute/set_vm.rb +0 -12
  161. data/lib/fog/hyperv/requests/compute/set_vm_bios.rb +0 -13
  162. data/lib/fog/hyperv/requests/compute/set_vm_dvd_drive.rb +0 -12
  163. data/lib/fog/hyperv/requests/compute/set_vm_firmware.rb +0 -13
  164. data/lib/fog/hyperv/requests/compute/set_vm_hard_disk_drive.rb +0 -12
  165. data/lib/fog/hyperv/requests/compute/set_vm_network_adapter.rb +0 -12
  166. data/lib/fog/hyperv/requests/compute/set_vm_network_adapter_vlan.rb +0 -12
  167. data/lib/fog/hyperv/requests/compute/set_vm_switch.rb +0 -13
  168. data/lib/fog/hyperv/requests/compute/start_vm.rb +0 -15
  169. data/lib/fog/hyperv/requests/compute/stop_vm.rb +0 -15
  170. data/lib/fog/model.rb +0 -91
  171. data/test/fog/hyperv_test.rb +0 -7
  172. data/test/test_helper.rb +0 -4
  173. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_cluster.json +0 -0
  174. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_cluster_node.json +0 -0
  175. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vhd.json +0 -0
  176. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_bios.json +0 -0
  177. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_dvd_drive.json +0 -0
  178. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_firmware.json +0 -0
  179. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_floppy_disk_drive.json +0 -0
  180. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_hard_disk_drive.json +0 -0
  181. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_host.json +0 -0
  182. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_network_adapter.json +0 -0
  183. /data/lib/fog/hyperv/{requests/compute → compute/requests}/mock_files/get_vm_switch.json +0 -0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Hyperv::Associations
4
+ class Collection < Fog::Associations::Default
5
+ private
6
+
7
+ def create_setter; end
8
+
9
+ def create_getter; end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Attributes
4
+ # Fog attribute type for handling DateTime values from PowerShell
5
+ class Hypervdatetime < Fog::Attributes::Default
6
+ private
7
+
8
+ # rubocop:disable Style/DocumentDynamicEvalDefinition
9
+
10
+ def create_setter
11
+ # Possible input values are;
12
+ # /Date(123456789)/ - time since unix epoch in milliseconds
13
+ # "2026-01-02T10:11:12Z" - DateTime in long-form parsable format
14
+ model.class_eval <<-SETTER, __FILE__, __LINE__ + 1
15
+ def #{name}=(new_#{name})
16
+ new_#{name} = new_#{name}.scan(/Date\\((\\d+)\\)/).flatten.first&.to_i if new_#{name}.include?('Date(')
17
+
18
+ if new_#{name}.respond_to?(:to_i)
19
+ attributes[:#{name}] = Fog::Time.at(new_#{name}.to_i / 1000.0)
20
+ else
21
+ attributes[:#{name}] = Fog::Time.parse(new_#{name}.to_s)
22
+ end
23
+ end
24
+ SETTER
25
+ end
26
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
27
+ end
28
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Attributes
4
+ # Fog attribute type for handling enums from PowelShell,
5
+ # where the value might be a number or string depending on the context
6
+ class Hypervenum < Default
7
+ attr_reader :values
8
+
9
+ def initialize(model, name, options)
10
+ @values = options.fetch(:values)
11
+
12
+ raise Fog::Hyperv::Errors::ServiceError, "#{values} is not a valid array or hash" \
13
+ unless %w[Array Hash].include?(values.class.to_s)
14
+
15
+ super
16
+ end
17
+
18
+ private
19
+
20
+ # rubocop:disable Style/DocumentDynamicEvalDefinition -- Reporting false positive
21
+
22
+ def ensure_value_getter
23
+ return if model.private_method_defined?(:"#{name}_values")
24
+
25
+ model.class_eval <<-VALUE_GETTER, __FILE__, __LINE__ + 1
26
+ # private
27
+ # def state_values
28
+ # { Unknown: 1, Running: 2 }.freeze
29
+ # end
30
+
31
+ private
32
+ def #{name}_values
33
+ #{values}.freeze
34
+ end
35
+ VALUE_GETTER
36
+ end
37
+
38
+ def create_setter
39
+ ensure_value_getter
40
+
41
+ # Add a setter that always stores a symbol value
42
+ model.class_eval <<-SETTER, __FILE__, __LINE__ + 1
43
+ # def state=(new_value)
44
+ # _values = state_values
45
+ # if new_value.is_a?(Numeric)
46
+ # # TODO: Better way to do class comparison in generated code
47
+ # if _values.class.to_s == 'Array'
48
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not in the range (0..\#{_values.length - 1})" \
49
+ # unless new_value >= 0 && new_value < _values.length
50
+ # attributes[:state] = _values[new_value]
51
+ # elsif _values.class.to_s == 'Hash'
52
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not one of \#{_values.values})" \
53
+ # unless _values.values.include? new_value
54
+ # attributes[:state] = _values.key(new_value)
55
+ # end
56
+ # elsif new_value.nil?
57
+ # attributes[:state] = nil
58
+ # else
59
+ # new_value = new_value.to_s.to_sym unless new_value.is_a? Symbol
60
+ # # Ensure values is the array of enum symbols
61
+ # _values = (_values.is_a?(Hash) ? _values.keys : _values)
62
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value.inspect} is not one of \#{_values})" \
63
+ # unless _values.include? new_value
64
+ # attributes[:state] = new_value
65
+ # end
66
+ # end
67
+
68
+ def #{name}=(new_value)
69
+ _values = #{name}_values
70
+ if new_value.is_a?(Numeric)
71
+ # TODO: Better way to do class comparison in generated code
72
+ if _values.class.to_s == 'Array'
73
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not in the range (0..\#{_values.length - 1})" \
74
+ unless new_value >= 0 && new_value < _values.length
75
+ attributes[:#{name}] = _values[new_value]
76
+ elsif _values.class.to_s == 'Hash'
77
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not one of \#{_values.values})" \
78
+ unless _values.values.include? new_value
79
+ attributes[:#{name}] = _values.key(new_value)
80
+ end
81
+ elsif new_value.nil?
82
+ attributes[:#{name}] = nil
83
+ else
84
+ new_value = new_value.to_s.to_sym unless new_value.is_a? Symbol
85
+ # Ensure values is the array of enum symbols
86
+ _values = (_values.is_a?(Hash) ? _values.keys : _values)
87
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value.inspect} is not one of \#{_values})" \
88
+ unless _values.include? new_value
89
+ attributes[:#{name}] = new_value
90
+ end
91
+ end
92
+ SETTER
93
+ end
94
+
95
+ def create_getter
96
+ ensure_value_getter
97
+
98
+ # Add a getter for <enum>_num to get the numeric value
99
+ model.class_eval <<-GETTER_NUM, __FILE__, __LINE__ + 1
100
+ # def state_num
101
+ # _values = state_values
102
+ # _value = attributes[:state]
103
+ #
104
+ # return nil if _value.nil?
105
+ # if _value.is_a?(Numeric)
106
+ # _value
107
+ # else
108
+ # if _values.is_a?(Hash)
109
+ # _values.send(:[], _value)
110
+ # else
111
+ # _values.index(_value)
112
+ # end
113
+ # end
114
+ # end
115
+
116
+
117
+ def #{name}_num
118
+ _values = #{name}_values
119
+ _value = attributes[:#{name}]
120
+
121
+ return nil if _value.nil?
122
+ if _value.is_a?(Numeric)
123
+ _value
124
+ else
125
+ if _values.is_a?(Hash)
126
+ _values.send(:[], _value)
127
+ else
128
+ _values.index(_value)
129
+ end
130
+ end
131
+ end
132
+ GETTER_NUM
133
+
134
+ # Add the default getter for the symbol value
135
+ super
136
+ end
137
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
138
+ end
139
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Attributes
4
+ # Fog attribute type for handling arrays of enums from PowerShell,
5
+ # where each value might be returned as a number or string depending on the context
6
+ class Hypervenumarray < Default
7
+ attr_reader :values
8
+
9
+ def initialize(model, name, options)
10
+ @values = options.fetch(:values, [])
11
+
12
+ raise Fog::Hyperv::Errors::ServiceError, "#{values} is not a valid array or hash" \
13
+ unless %w[Array Hash].include?(values.class.to_s)
14
+
15
+ super
16
+ end
17
+
18
+ private
19
+
20
+ # rubocop:disable Style/DocumentDynamicEvalDefinition -- Reporting false positive
21
+
22
+ def ensure_value_getter
23
+ return if model.private_method_defined?(:"#{name}_values")
24
+
25
+ model.class_eval <<-VALUE_GETTER, __FILE__, __LINE__ + 1
26
+ # private
27
+ # def state_values
28
+ # { Unknown: 1, Running: 2 }.freeze
29
+ # end
30
+
31
+ private
32
+ def #{name}_values
33
+ #{values}.freeze
34
+ end
35
+ VALUE_GETTER
36
+ end
37
+
38
+ def create_setter
39
+ ensure_value_getter
40
+
41
+ # Add a setter that always stores a symbol value
42
+ model.class_eval <<-SETTER, __FILE__, __LINE__ + 1
43
+ # def state=(new_values)
44
+ # _values = state_values
45
+ # attributes[:state] = []
46
+ # new_values.each do |new_value|
47
+ # next unless new_value
48
+ # if new_value.is_a?(Numeric)
49
+ # # TODO: Better way to do class comparison in generated code
50
+ # if _values.class.to_s == 'Array'
51
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not in the range (0..\#{_values.length - 1})" \
52
+ # unless new_value >= 0 && new_value < _values.length
53
+ # attributes[:state] << _values[new_value]
54
+ # elsif _values.class.to_s == 'Hash'
55
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not one of \#{_values.values})" \
56
+ # unless _values.values.include? new_value
57
+ # attributes[:state] << _values.key(new_value)
58
+ # end
59
+ # else
60
+ # new_value = new_value.to_s.to_sym unless new_value.is_a? Symbol
61
+ # # Ensure values is the array of enum symbols
62
+ # _values = (_values.is_a?(Hash) ? _values.keys : _values)
63
+ # raise Fog::Hyperv::Errors::ServiceError, "\#{new_value.inspect} is not one of \#{_values})" \
64
+ # unless _values.include? new_value
65
+ # attributes[:state] << new_value
66
+ # end
67
+ # end
68
+ # end
69
+
70
+ def #{name}=(new_values)
71
+ _values = #{name}_values
72
+ new_values = [new_values].flatten unless new_values.is_a? Array
73
+ attributes[:#{name}] = []
74
+ new_values.each do |new_value|
75
+ next unless new_value
76
+
77
+ if new_value.is_a?(Numeric)
78
+ # TODO: Better way to do class comparison in generated code
79
+ if _values.class.to_s == 'Array'
80
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not in the range (0..\#{_values.length - 1})" \
81
+ unless new_value >= 0 && new_value < _values.length
82
+ attributes[:#{name}] << _values[new_value]
83
+ elsif _values.class.to_s == 'Hash'
84
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value} is not one of \#{_values.values})" \
85
+ unless _values.values.include? new_value
86
+ attributes[:#{name}] << _values.key(new_value)
87
+ end
88
+ else
89
+ new_value = new_value.to_s.to_sym unless new_value.is_a? Symbol
90
+ # Ensure values is the array of enum symbols
91
+ _values = (_values.is_a?(Hash) ? _values.keys : _values)
92
+ raise Fog::Hyperv::Errors::ServiceError, "\#{new_value.inspect} is not one of \#{_values})" \
93
+ unless _values.include? new_value
94
+ attributes[:#{name}] << new_value
95
+ end
96
+ end
97
+ end
98
+ SETTER
99
+ end
100
+
101
+ def create_getter
102
+ ensure_value_getter
103
+
104
+ # Add a getter for <enum>_num to get the numeric value
105
+ model.class_eval <<-GETTER_NUM, __FILE__, __LINE__ + 1
106
+ # def state_num
107
+ # _values = state_values
108
+ # _value = attributes[:state]
109
+ #
110
+ # return nil if _value.nil?
111
+ # _value.map do |v|
112
+ # if v.is_a?(Numeric)
113
+ # v
114
+ # else
115
+ # if _values.is_a?(Hash)
116
+ # _values.send(:[], v)
117
+ # else
118
+ # _values.index(v)
119
+ # end
120
+ # end
121
+ # end
122
+ # end
123
+
124
+
125
+ def #{name}_num
126
+ _values = #{name}_values
127
+ _value = attributes[:#{name}]
128
+
129
+ return nil if _value.nil?
130
+ _value.map do |v|
131
+ if v.is_a?(Numeric)
132
+ v
133
+ else
134
+ if _values.is_a?(Hash)
135
+ _values.send(:[], v)
136
+ else
137
+ _values.index(v)
138
+ end
139
+ end
140
+ end
141
+ end
142
+ GETTER_NUM
143
+
144
+ # Add the default getter for the symbol value
145
+ super
146
+ end
147
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
148
+ end
149
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Attributes
4
+ # Fog attribute type for handling TimeSpan values from PowerShell
5
+ class Hypervtimespan < Fog::Attributes::Default
6
+ private
7
+
8
+ # rubocop:disable Style/DocumentDynamicEvalDefinition
9
+
10
+ def create_setter
11
+ # Possible input values are;
12
+ # 00:00:00 - string-converted TimeSpan
13
+ # {hours: 0, minutes: 0... total_seconds: 0} - hash containing the TimeSpan data
14
+ model.class_eval <<-SETTER, __FILE__, __LINE__ + 1
15
+ def #{name}=(new_#{name})
16
+ if new_#{name}.is_a?(Hash)
17
+ attributes[:#{name}] = new_#{name}[:total_seconds]
18
+ else
19
+ h, m, s = new_#{name}.split(':').map(&:to_f)
20
+ attributes[:#{name}] = h * 3600 + m * 60 + s
21
+ end
22
+ end
23
+ SETTER
24
+ end
25
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
26
+ end
27
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Hyperv
4
+ module ModelExtends
5
+ # Attach a collection of sub-models
6
+ # @param name [Symbol] the attribute name to store the collection under
7
+ # @param collection_name [Symbol] the name of the collection on the service
8
+ # @param options [Hash] the options to create the collection attachment with
9
+ # @see Fog::Hyperv::Associations::Collection
10
+ def collection(name, collection_name = nil, options = {}) # rubocop:disable Style/OptionHash -- upstream design
11
+ collection_name ||= name
12
+ Fog::Hyperv::Associations::Collection.new(self, name, collection_name, options)
13
+
14
+ case to_s
15
+ when 'Fog::Hyperv::Compute::Server'
16
+ define_method name do
17
+ associations[name] ||= service.send(collection_name, vm: self, computer_name: computer_name, vm_id: id)
18
+ end
19
+ when 'Fog::Hyperv::Compute::Host'
20
+ define_method name do
21
+ associations[name] ||= service.send(collection_name, computer: self, computer_name: computer_name)
22
+ end
23
+ else
24
+ raise "Unknown class #{self}"
25
+ end
26
+
27
+ define_method :"#{name}=" do |data|
28
+ assoc = associations[name] || send(name)
29
+ assoc.clear
30
+ assoc.instance_variable_set :@loaded, true
31
+ [data].flatten.each do |obj|
32
+ obj = assoc.new obj if obj.is_a?(Hash)
33
+ assoc << obj
34
+ end
35
+ assoc
36
+ end
37
+ end
38
+ end
39
+
40
+ module ModelIncludes
41
+ # Has the model been modified
42
+ # @return [Boolean] have any attributes changed since the model was retrieved
43
+ def dirty?
44
+ dirty.any?
45
+ end
46
+
47
+ # Get all dirty attributes
48
+ # @return [Array<Symbol>] all the attributes that have changed since the model was retrieved
49
+ def dirty
50
+ potential = attributes.slice(*self.class.attributes)
51
+ return potential unless old
52
+
53
+ potential.reject { |k, v| old.attributes[k] == v }.keys
54
+ end
55
+
56
+ # Get the VM this model is attached to
57
+ # @return [Fog::Hyperv::Compute::Server,nil] the VM this model is attached to, if any
58
+ def vm
59
+ return @vm if @vm
60
+ return unless respond_to?(:vm_id) && vm_id
61
+
62
+ @vm ||= service.servers.get vm_id
63
+ end
64
+
65
+ # Get the Computer this model is attached to
66
+ # @return [Fog::Hyperv::Compute::Host,nil] the Computer this model is attached to, if any
67
+ def computer
68
+ return @computer if @computer
69
+ return @computer ||= service.hosts.get(computer_name) if respond_to?(:computer_name) && computer_name
70
+
71
+ @computer ||= vm&.computer
72
+ end
73
+
74
+ # Get the Cluster this model is part of
75
+ # @return [Fog::Hyperv::Compute::Cluster,nil] the Cluster this model is part of, if any
76
+ def cluster
77
+ return @cluster if @cluster
78
+ return unless respond_to?(:cluster_name) && cluster_name
79
+
80
+ @cluster ||= service.clusters.get cluster_name
81
+ end
82
+
83
+ private
84
+
85
+ def logger
86
+ service.logger
87
+ end
88
+
89
+ # Has any of the listed attributes been modified
90
+ # @param attrs [Symbol] the attributes to check for modification
91
+ # @param all [Boolean] check if all listed attributes have changed, instead of any
92
+ # @return [Boolean] are any/all of the listed attributes modified
93
+ def changed?(*attrs, all: false)
94
+ return false unless old
95
+
96
+ changed = dirty
97
+ if all
98
+ attrs.all? { |attr| changed.include? attr }
99
+ else
100
+ attrs.any? { |attr| changed.include? attr }
101
+ end
102
+ end
103
+
104
+ # Return the modified value of the given attribute - if any
105
+ # @return [Object,nil] the modified value of the attribute, or nil if it's unmodified
106
+ def changed!(attr)
107
+ changed?(attr) ? attributes[attr] : nil
108
+ end
109
+
110
+ # Return the old values of the model - i.e. what's stored in Hyper-V
111
+ # @return [Object,nil] the old copy of the model, or nil if there's no older version available
112
+ def old
113
+ @old ||= (persisted? ? dup.reload : nil)
114
+ end
115
+ end
116
+
117
+ # A slightly specialized Fog::Model which includes shared Hyper-V functionality
118
+ class Model < Fog::Model
119
+ extend Fog::Hyperv::ModelExtends
120
+ include Fog::Hyperv::ModelIncludes
121
+
122
+ def initialize(attributes = {})
123
+ @vm = attributes.delete :vm
124
+ self.attributes[:vm] = @vm if self.class.attributes.include? :vm
125
+ @computer = attributes.delete :computer
126
+ self.attributes[:computer] = @computer if self.class.attributes.include? :computer
127
+ @cluster = attributes.delete :cluster
128
+ self.attributes[:cluster] = @cluster if self.class.attributes.include? :cluster
129
+
130
+ super
131
+
132
+ @old = dup if persisted?
133
+ end
134
+
135
+ def merge_attributes(attributes = {})
136
+ super
137
+
138
+ @old = dup
139
+ self
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fog::Hyperv::Utils::Powershell
4
+ # Build a Powershell option map from a set of keyword arguments
5
+ # @param _optmap_name [String] the name of the option map to generate
6
+ # @param _ps_version [Integer] the major version of PowerShell to generate the option map for
7
+ # @param _from_json [Boolean] should the option map be built from JSON data
8
+ # @param options [Hash] the options to convert into a PowerShell option map
9
+ def self.build_optmap(_optmap_name: 'FogArgs', _ps_version: 5, _from_json: true, **_options)
10
+ ps_opts = Fog::Hyperv.camelize(_options)
11
+ if _from_json
12
+ if _ps_version >= 6
13
+ ["$#{_optmap_name} = ConvertFrom-Json -AsHashtable '#{Fog::JSON.encode ps_opts}'"]
14
+ else
15
+ [
16
+ [
17
+ "$FogJsonObject = '#{Fog::JSON.encode ps_opts}'",
18
+ '$FogJsonParameters = ConvertFrom-Json -InputObject $FogJsonObject',
19
+ "$#{_optmap_name} = @{}",
20
+ "$FogJsonParameters.psobject.properties | Foreach { $#{_optmap_name}[$_.Name] = $_.Value }"
21
+ ].join('; ')
22
+ ]
23
+ end
24
+ else
25
+ args = ps_opts.map do |k, v|
26
+ "'#{k}'=#{Fog::Hyperv.shell_quote(v, always: true)}"
27
+ end
28
+
29
+ ["$#{_optmap_name} = @{#{args.join ';'}}"]
30
+ end
31
+ end
32
+
33
+ # Build a Powershell cmdlet call
34
+ # @param cmdlet [String] the PowerShell cmdlet to call
35
+ # @param args [Hash] the argument to call the cmdlet with
36
+ # @param _ps_version [Integer] the major version of PowerShell the call is being made for
37
+ #
38
+ # @example Running a simple cmdlet
39
+ # build_call 'Get-VM', { name: 'example VM' }, _ps_version: 7
40
+ # => "$Fogwozmqayrgsyd = ConvertFrom-Json -AsHashtable '{"Name": "example VM"}\nGet-VM @Fogwozmqayrgsyd"
41
+ def self.build_call(cmdlet, args = {}, _ps_version: 5)
42
+ return [cmdlet.gsub('@Args', '')].flatten if args.empty?
43
+
44
+ id = (cmdlet.hash ^ args.hash).abs.to_s(36)
45
+ optmap = "Fog#{id}"
46
+
47
+ commands = []
48
+ commands += build_optmap(_optmap_name: optmap, _ps_version: _ps_version, **args)
49
+ commands << if cmdlet.include? '@Args'
50
+ cmdlet.gsub('@Args', "@#{optmap}")
51
+ else
52
+ "#{cmdlet} @#{optmap}"
53
+ end
54
+ commands
55
+ end
56
+
57
+ # Convert Ruby data to PowerShell equivalents
58
+ # @param data [Object] the Ruby data to convert
59
+ # @param always [Boolean] should the data be included even if the equivalent would be a no-op
60
+ def self.shell_quote(data, always: false)
61
+ case data
62
+ when String
63
+ if !data.start_with?('$') && (data =~ /(^$)|\s/ || always)
64
+ data.gsub('`', '``')
65
+ .gsub(/\0/, '`0')
66
+ .gsub("\n", '`n')
67
+ .gsub("\r", '`r')
68
+ .inspect
69
+ .gsub('\"', '`"')
70
+ .gsub('\\\\', '\\')
71
+ else
72
+ data
73
+ end
74
+ when Hash
75
+ raise 'Hashes need to be run through build_optmap'
76
+ when Array
77
+ "@(#{data.map { |e| shell_quoted(e, always: true) }.join(', ')})"
78
+ when FalseClass
79
+ '$false'
80
+ when TrueClass
81
+ '$true'
82
+ when nil
83
+ '$null'
84
+ else
85
+ shell_quoted data.to_s
86
+ end
87
+ end
88
+ end