foreman_nutanix 0.1.4 → 0.1.6
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/Rakefile +0 -6
- data/app/lib/foreman_nutanix/nutanix_adapter.rb +14 -10
- data/app/models/foreman_nutanix/nutanix.rb +69 -63
- data/app/models/foreman_nutanix/nutanix_compute.rb +90 -42
- data/app/views/compute_resources_vms/form/nutanix/_base.html.erb +35 -0
- data/app/views/compute_resources_vms/show/_nutanix.html.erb +2 -1
- data/lib/foreman_nutanix/gpu_profile.rb +54 -0
- data/lib/foreman_nutanix/shim_client.rb +93 -0
- data/lib/foreman_nutanix/version.rb +1 -1
- data/lib/foreman_nutanix.rb +2 -0
- data/test/README.md +46 -0
- data/test/gpu_profile_test.rb +98 -0
- data/test/nutanix_compute_gpu_test.rb +207 -0
- data/test/nutanix_compute_test.rb +62 -0
- data/test/shim_client_test.rb +257 -0
- data/test/test_helper.rb +15 -0
- metadata +17 -3
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ShimClientTest < Minitest::Test
|
|
4
|
+
# --- Fakes injected through the http: keyword -----------------------------
|
|
5
|
+
|
|
6
|
+
# Stands in for a Net::HTTP connection object.
|
|
7
|
+
class FakeConnection
|
|
8
|
+
attr_reader :host, :port, :requests
|
|
9
|
+
attr_accessor :use_ssl
|
|
10
|
+
|
|
11
|
+
def initialize(host, port, response)
|
|
12
|
+
@host = host
|
|
13
|
+
@port = port
|
|
14
|
+
@response = response
|
|
15
|
+
@requests = []
|
|
16
|
+
@use_ssl = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def request(req)
|
|
20
|
+
@requests << req
|
|
21
|
+
@response
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Stands in for the Net::HTTP class itself.
|
|
26
|
+
class FakeHttp
|
|
27
|
+
attr_reader :connections
|
|
28
|
+
|
|
29
|
+
def initialize(response)
|
|
30
|
+
@response = response
|
|
31
|
+
@connections = []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def new(host, port)
|
|
35
|
+
conn = FakeConnection.new(host, port, @response)
|
|
36
|
+
@connections << conn
|
|
37
|
+
conn
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def last_connection
|
|
41
|
+
@connections.last
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def last_request
|
|
45
|
+
last_connection.requests.last
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def stub_response(klass = Net::HTTPOK, code: '200', body: '{}')
|
|
50
|
+
response = klass.new('1.1', code, 'Stub')
|
|
51
|
+
response.instance_variable_set(:@body, body)
|
|
52
|
+
response.instance_variable_set(:@read, true)
|
|
53
|
+
response
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def client(base_url = 'http://shim.example:8000', response: stub_response)
|
|
57
|
+
http = FakeHttp.new(response)
|
|
58
|
+
[ForemanNutanix::ShimClient.new(base_url, http: http), http]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def with_env(value)
|
|
62
|
+
previous = ENV['NUTANIX_SHIM_SERVER_ADDR']
|
|
63
|
+
had_key = ENV.key?('NUTANIX_SHIM_SERVER_ADDR')
|
|
64
|
+
if value.nil?
|
|
65
|
+
ENV.delete('NUTANIX_SHIM_SERVER_ADDR')
|
|
66
|
+
else
|
|
67
|
+
ENV['NUTANIX_SHIM_SERVER_ADDR'] = value
|
|
68
|
+
end
|
|
69
|
+
yield
|
|
70
|
+
ensure
|
|
71
|
+
if had_key
|
|
72
|
+
ENV['NUTANIX_SHIM_SERVER_ADDR'] = previous
|
|
73
|
+
else
|
|
74
|
+
ENV.delete('NUTANIX_SHIM_SERVER_ADDR')
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# --- Base URL -------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
def test_base_url_defaults_to_localhost_when_env_is_unset
|
|
81
|
+
with_env(nil) do
|
|
82
|
+
assert_equal 'http://localhost:8000', ForemanNutanix::ShimClient.new.base_url
|
|
83
|
+
assert_equal 'http://localhost:8000', ForemanNutanix::ShimClient.default_base_url
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_base_url_comes_from_env_when_set
|
|
88
|
+
with_env('http://shim.internal:9000') do
|
|
89
|
+
assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.new.base_url
|
|
90
|
+
assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.default_base_url
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_explicit_base_url_wins_over_env
|
|
95
|
+
with_env('http://shim.internal:9000') do
|
|
96
|
+
assert_equal 'http://explicit:1234', ForemanNutanix::ShimClient.new('http://explicit:1234').base_url
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_trailing_slash_is_chomped
|
|
101
|
+
shim = ForemanNutanix::ShimClient.new('http://shim.example:8000/')
|
|
102
|
+
assert_equal 'http://shim.example:8000', shim.base_url
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_trailing_slash_from_env_is_chomped
|
|
106
|
+
with_env('http://shim.internal:9000/') do
|
|
107
|
+
assert_equal 'http://shim.internal:9000', ForemanNutanix::ShimClient.new.base_url
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# --- Verbs and path construction -----------------------------------------
|
|
112
|
+
|
|
113
|
+
def test_get_builds_a_get_request_at_the_joined_path
|
|
114
|
+
shim, http = client
|
|
115
|
+
shim.get('/api/v1/vmm/list-images')
|
|
116
|
+
|
|
117
|
+
request = http.last_request
|
|
118
|
+
assert_instance_of Net::HTTP::Get, request
|
|
119
|
+
assert_equal '/api/v1/vmm/list-images', request.path
|
|
120
|
+
assert_equal 'shim.example', http.last_connection.host
|
|
121
|
+
assert_equal 8000, http.last_connection.port
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_post_builds_a_post_request_at_the_joined_path
|
|
125
|
+
shim, http = client
|
|
126
|
+
shim.post('/api/v1/vmm/vms/abc/power-state', { action: 'POWER_ON' })
|
|
127
|
+
|
|
128
|
+
assert_instance_of Net::HTTP::Post, http.last_request
|
|
129
|
+
assert_equal '/api/v1/vmm/vms/abc/power-state', http.last_request.path
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_delete_builds_a_delete_request_at_the_joined_path
|
|
133
|
+
shim, http = client
|
|
134
|
+
shim.delete('/api/v1/vmm/vms/abc')
|
|
135
|
+
|
|
136
|
+
assert_instance_of Net::HTTP::Delete, http.last_request
|
|
137
|
+
assert_equal '/api/v1/vmm/vms/abc', http.last_request.path
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_path_is_joined_to_a_base_url_that_had_a_trailing_slash
|
|
141
|
+
http = FakeHttp.new(stub_response)
|
|
142
|
+
ForemanNutanix::ShimClient.new('http://shim.example:8000/', http: http).get('/api/v1/vmm/list-vms')
|
|
143
|
+
|
|
144
|
+
assert_equal '/api/v1/vmm/list-vms', http.last_request.path
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# --- Body encoding --------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
def test_post_json_encodes_the_body_and_sets_content_type
|
|
150
|
+
shim, http = client
|
|
151
|
+
shim.post('/api/v1/vmm/provision-vm', { name: 'vm-1', num_sockets: 2 })
|
|
152
|
+
|
|
153
|
+
assert_equal 'application/json', http.last_request['Content-Type']
|
|
154
|
+
assert_equal({ 'name' => 'vm-1', 'num_sockets' => 2 }, JSON.parse(http.last_request.body))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def test_post_without_a_body_sends_no_body_and_no_content_type
|
|
158
|
+
shim, http = client
|
|
159
|
+
shim.post('/api/v1/vmm/noop')
|
|
160
|
+
|
|
161
|
+
assert_nil http.last_request.body
|
|
162
|
+
assert_nil http.last_request['Content-Type']
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def test_get_sends_no_body_and_no_content_type
|
|
166
|
+
shim, http = client
|
|
167
|
+
shim.get('/api/v1/vmm/list-vms')
|
|
168
|
+
|
|
169
|
+
assert_nil http.last_request.body
|
|
170
|
+
assert_nil http.last_request['Content-Type']
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# --- Scheme ---------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
def test_https_is_inferred_from_the_scheme
|
|
176
|
+
http = FakeHttp.new(stub_response)
|
|
177
|
+
ForemanNutanix::ShimClient.new('https://shim.example', http: http).get('/api/v1/vmm/list-vms')
|
|
178
|
+
|
|
179
|
+
assert_equal true, http.last_connection.use_ssl
|
|
180
|
+
assert_equal 443, http.last_connection.port
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def test_http_scheme_does_not_enable_ssl
|
|
184
|
+
shim, http = client
|
|
185
|
+
shim.get('/api/v1/vmm/list-vms')
|
|
186
|
+
|
|
187
|
+
assert_equal false, http.last_connection.use_ssl
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# --- Response -------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
def test_success_is_true_for_200
|
|
193
|
+
shim, = client(response: stub_response(Net::HTTPOK, code: '200'))
|
|
194
|
+
response = shim.get('/whatever')
|
|
195
|
+
|
|
196
|
+
assert_equal true, response.success?
|
|
197
|
+
assert_equal '200', response.code
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def test_success_is_false_for_404
|
|
201
|
+
shim, = client(response: stub_response(Net::HTTPNotFound, code: '404', body: 'not found'))
|
|
202
|
+
response = shim.get('/whatever')
|
|
203
|
+
|
|
204
|
+
assert_equal false, response.success?
|
|
205
|
+
assert_equal '404', response.code
|
|
206
|
+
assert_equal 'not found', response.body
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_success_is_false_for_500
|
|
210
|
+
error = stub_response(Net::HTTPInternalServerError, code: '500', body: '<html>boom</html>')
|
|
211
|
+
shim, = client(response: error)
|
|
212
|
+
response = shim.get('/whatever')
|
|
213
|
+
|
|
214
|
+
assert_equal false, response.success?
|
|
215
|
+
assert_equal '500', response.code
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def test_no_content_is_true_only_for_204
|
|
219
|
+
shim, = client(response: stub_response(Net::HTTPNoContent, code: '204', body: nil))
|
|
220
|
+
assert_equal true, shim.get('/whatever').no_content?
|
|
221
|
+
|
|
222
|
+
shim_ok, = client(response: stub_response(Net::HTTPOK, code: '200'))
|
|
223
|
+
assert_equal false, shim_ok.get('/whatever').no_content?
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def test_json_parses_the_body
|
|
227
|
+
shim, = client(response: stub_response(Net::HTTPOK, body: '[{"ext_id":"abc"}]'))
|
|
228
|
+
|
|
229
|
+
assert_equal [{ 'ext_id' => 'abc' }], shim.get('/whatever').json
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def test_json_propagates_parser_error_on_non_json_bodies
|
|
233
|
+
error = stub_response(Net::HTTPInternalServerError, code: '500', body: '<html>boom</html>')
|
|
234
|
+
shim, = client(response: error)
|
|
235
|
+
|
|
236
|
+
assert_raises(JSON::ParserError) { shim.get('/whatever').json }
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# --- normalize_uuid -------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
def test_normalize_uuid_strips_a_prefix
|
|
242
|
+
assert_equal 'the-uuid', ForemanNutanix::ShimClient.normalize_uuid('ZXJnb24=:the-uuid')
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def test_normalize_uuid_leaves_a_bare_uuid_alone
|
|
246
|
+
assert_equal 'the-uuid', ForemanNutanix::ShimClient.normalize_uuid('the-uuid')
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def test_normalize_uuid_coerces_non_strings
|
|
250
|
+
assert_equal '', ForemanNutanix::ShimClient.normalize_uuid(nil)
|
|
251
|
+
assert_equal '42', ForemanNutanix::ShimClient.normalize_uuid(42)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def test_normalize_uuid_keeps_only_the_last_segment
|
|
255
|
+
assert_equal 'c', ForemanNutanix::ShimClient.normalize_uuid('a:b:c')
|
|
256
|
+
end
|
|
257
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
|
|
3
|
+
# Standalone: no Rails, no Foreman, no database. See test/README.md for what
|
|
4
|
+
# that rules out.
|
|
5
|
+
require 'foreman_nutanix/shim_client'
|
|
6
|
+
|
|
7
|
+
# NutanixCompute is a plain object, but it logs in nearly every method. This is
|
|
8
|
+
# the whole of the Rails surface the suite needs; it lives here rather than in
|
|
9
|
+
# one test file so a second file defining it cannot redefine the first's.
|
|
10
|
+
require 'logger'
|
|
11
|
+
module Rails
|
|
12
|
+
def self.logger
|
|
13
|
+
@logger ||= Logger.new(IO::NULL)
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_nutanix
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miles Granger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rdoc
|
|
@@ -54,10 +54,18 @@ files:
|
|
|
54
54
|
- config/routes.rb
|
|
55
55
|
- lib/foreman_nutanix.rb
|
|
56
56
|
- lib/foreman_nutanix/engine.rb
|
|
57
|
+
- lib/foreman_nutanix/gpu_profile.rb
|
|
58
|
+
- lib/foreman_nutanix/shim_client.rb
|
|
57
59
|
- lib/foreman_nutanix/version.rb
|
|
58
60
|
- lib/tasks/foreman_nutanix_tasks.rake
|
|
59
61
|
- locale/foreman_nutanix.pot
|
|
60
62
|
- package.json
|
|
63
|
+
- test/README.md
|
|
64
|
+
- test/gpu_profile_test.rb
|
|
65
|
+
- test/nutanix_compute_gpu_test.rb
|
|
66
|
+
- test/nutanix_compute_test.rb
|
|
67
|
+
- test/shim_client_test.rb
|
|
68
|
+
- test/test_helper.rb
|
|
61
69
|
- webpack/global_index.js
|
|
62
70
|
- webpack/global_test_setup.js
|
|
63
71
|
- webpack/index.js
|
|
@@ -94,4 +102,10 @@ rubygems_version: 3.4.19
|
|
|
94
102
|
signing_key:
|
|
95
103
|
specification_version: 4
|
|
96
104
|
summary: Nutanix plugin for Foreman
|
|
97
|
-
test_files:
|
|
105
|
+
test_files:
|
|
106
|
+
- test/README.md
|
|
107
|
+
- test/gpu_profile_test.rb
|
|
108
|
+
- test/nutanix_compute_gpu_test.rb
|
|
109
|
+
- test/nutanix_compute_test.rb
|
|
110
|
+
- test/shim_client_test.rb
|
|
111
|
+
- test/test_helper.rb
|