Skip to content

Commit 2279869

Browse files
authored
Merge pull request #594 from Hyperkid123/add-pxeserver-crud
Added PxeServer create, update and delete actions
2 parents aa2d4fe + 021be88 commit 2279869

File tree

5 files changed

+273
-2
lines changed

5 files changed

+273
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Api
2+
class PxeMenusController < BaseController
3+
end
4+
end
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,78 @@
11
module Api
22
class PxeServersController < BaseController
33
include Subcollections::PxeImages
4+
include Subcollections::PxeMenus
5+
INVALID_ATTRIBUTES = {
6+
"PxeServer" => %w[id href], # Cannot update or create these
7+
}.freeze
8+
PXE_ATTRIBUTES = {
9+
"PxeServer" => %w[name uri],
10+
"PxeMenu" => %w[file_name],
11+
"Authentication" => %w[userid password]
12+
}.freeze
13+
14+
def create_resource(_type, _id, data = {})
15+
authentication = data.delete('authentication')
16+
menus = data.delete('pxe_menus')
17+
validate_data_for('PxeServer', data)
18+
19+
PxeServer.transaction do
20+
server = collection_class(:pxe_servers).new(data)
21+
# generates uir_prefix which checks if server needs authentication or not
22+
server.verify_uri_prefix_before_save
23+
24+
if server.requires_credentials? && server.missing_credentials?
25+
validate_data_for('Authentication', authentication || {})
26+
server.update_authentication({:default => authentication.compact}, {:save => true})
27+
end
28+
29+
server.pxe_menus = create_pxe_menus(menus) if menus
30+
31+
if server.invalid?
32+
raise BadRequestError, "Failed to add a pxe server - #{server.errors.full_messages.join(', ')}"
33+
end
34+
35+
server.save
36+
server
37+
end
38+
end
39+
40+
def delete_resource(_type, id = nil, data = nil)
41+
raise BadRequestError, "Must specify an id for deleting a pxe server" unless id
42+
43+
super
44+
end
45+
46+
def edit_resource(type, id, data)
47+
server = resource_search(id, type, collection_class(:pxe_servers))
48+
menus = data.delete('pxe_menus')
49+
authentication = data.delete('authentication')
50+
PxeServer.transaction do
51+
if menus
52+
server.pxe_menus.clear
53+
data['pxe_menus'] = create_pxe_menus(menus)
54+
end
55+
server.update!(data)
56+
server.update_authentication({:default => authentication.transform_keys(&:to_sym)}, {:save => true}) if authentication && server.requires_credentials?
57+
server
58+
end
59+
end
60+
61+
private
62+
63+
def create_pxe_menus(menus)
64+
menus.each do |menu|
65+
validate_data_for('PxeMenu', menu)
66+
end
67+
menus.map do |menu|
68+
collection_class(:pxe_menus).create(menu)
69+
end
70+
end
71+
72+
def validate_data_for(klass, data)
73+
bad_attrs = []
74+
PXE_ATTRIBUTES[klass].each { |attr| bad_attrs << attr if data[attr].blank? }
75+
raise BadRequestError, "Missing attribute(s) #{bad_attrs.join(', ')} for creating a #{klass}" if bad_attrs.present?
76+
end
477
end
578
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Api
2+
module Subcollections
3+
module PxeMenus
4+
def pxe_menus_query_resource(object)
5+
object.pxe_menus
6+
end
7+
end
8+
end
9+
end

config/api.yml

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2393,23 +2393,71 @@
23932393
:get:
23942394
- :name: read
23952395
:identifier: pxe_server_view
2396+
:pxe_menus:
2397+
:description: PXE Menus
2398+
:identifier: pxe_server_accord
2399+
:options:
2400+
- :collection
2401+
:verbs: *gpppd
2402+
:klass: PxeMenu
2403+
:collection_actions:
2404+
:get:
2405+
- :name: read
2406+
:identifier: pxe_server_view
2407+
:post:
2408+
- :name: create
2409+
:identifier: pxe_server_create
2410+
:subresource_actions:
2411+
:get:
2412+
- :name: read
2413+
:identifier: pxe_server_view
2414+
:subcollection_actions:
2415+
:get:
2416+
- :name: read
2417+
:identifier: pxe_server_view
2418+
:post:
2419+
- :name: create
2420+
:identifier: pxe_server_create
23962421
:pxe_servers:
23972422
:description: PXE Servers
23982423
:identifier: pxe_server_accord
23992424
:options:
24002425
- :collection
2401-
:verbs: *g
2426+
:verbs: *gpppd
24022427
:klass: PxeServer
24032428
:subcollections:
24042429
- :pxe_images
2430+
- :pxe_menus
24052431
:collection_actions:
2432+
:post:
2433+
- :name: create
2434+
:identifier: pxe_server_create
2435+
- :name: edit
2436+
:identifier: pxe_server_edit
2437+
:patch:
2438+
- :name: edit
2439+
:identifier: pxe_server_edit
2440+
:delete:
2441+
- :name: delete
2442+
:identifier: pxe_server_delete
24062443
:get:
24072444
- :name: read
24082445
:identifier: pxe_server_view
24092446
:resource_actions:
24102447
:get:
24112448
- :name: read
24122449
:identifier: pxe_server_view
2450+
:patch:
2451+
- :name: edit
2452+
:identifier: pxe_server_edit
2453+
:post:
2454+
- :name: create
2455+
:identifier: pxe_server_create
2456+
- :name: edit
2457+
:identifier: pxe_server_edit
2458+
:delete:
2459+
- :name: delete
2460+
:identifier: pxe_server_delete
24132461
:quotas:
24142462
:description: TenantQuotas
24152463
:options:

spec/requests/pxe_servers_spec.rb

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
RSpec.describe 'PxeServers API' do
2-
let!(:pxe_server) { FactoryBot.create(:pxe_server) }
2+
let(:pxe_server) { FactoryBot.build(:pxe_server).tap { |x| x.update_authentication(:default => {:userid => 'foo', :password => 'bar'}) } }
33
let!(:pxe_image_1) { FactoryBot.create(:pxe_image, :pxe_server => pxe_server) }
44
let!(:pxe_image_2) { FactoryBot.create(:pxe_image, :pxe_server => pxe_server) }
5+
let!(:pxe_menu_1) { FactoryBot.create(:pxe_menu, :pxe_server => pxe_server) }
56

67
describe 'GET /api/pxe_servers' do
78
let(:url) { api_pxe_servers_url }
@@ -90,4 +91,140 @@
9091
expect(response).to have_http_status(:forbidden)
9192
end
9293
end
94+
95+
describe 'GET /api/pxe_servers/:id/pxe_menus' do
96+
let(:url) { "/api/pxe_servers/#{pxe_server.id}/pxe_menus" }
97+
98+
it 'lists all pxe menus of a pxe server' do
99+
api_basic_authorize subcollection_action_identifier(:pxe_servers, :pxe_menus, :read, :get)
100+
get(url)
101+
expect_result_resources_to_include_hrefs(
102+
"resources",
103+
[
104+
api_pxe_server_pxe_menu_url(nil, pxe_server, pxe_menu_1)
105+
]
106+
)
107+
expect(response).to have_http_status(:ok)
108+
end
109+
110+
it 'forbids access without an appropriate role' do
111+
api_basic_authorize
112+
get(url)
113+
expect(response).to have_http_status(:forbidden)
114+
end
115+
end
116+
117+
describe 'GET /api/pxe_servers/:id/pxe_menus/:id' do
118+
let(:url) { "/api/pxe_servers/#{pxe_server.id}/pxe_menus/#{pxe_menu_1.id}" }
119+
120+
it "will show a single pxe menu of a pxe server" do
121+
api_basic_authorize subcollection_action_identifier(:pxe_servers, :pxe_images, :read, :get)
122+
get(url)
123+
expect_result_to_match_hash(
124+
response.parsed_body,
125+
"href" => api_pxe_server_pxe_menu_url(nil, pxe_server, pxe_menu_1),
126+
"id" => pxe_menu_1.id.to_s,
127+
"pxe_server_id" => pxe_server.id.to_s,
128+
"file_name" => pxe_menu_1.file_name
129+
)
130+
expect(response).to have_http_status(:ok)
131+
end
132+
133+
it 'forbids access without an appropriate role' do
134+
api_basic_authorize
135+
get(url)
136+
expect(response).to have_http_status(:forbidden)
137+
end
138+
end
139+
140+
describe 'POST /api/pxe_servers/' do
141+
let(:url) { "/api/pxe_servers/" }
142+
143+
it 'create new pxe server' do
144+
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
145+
post(
146+
url,
147+
:params => {
148+
:name => 'test server',
149+
:uri => 'bar://quax',
150+
:authentication => {
151+
:userid => 'foo',
152+
:password => 'bar'
153+
}
154+
}
155+
)
156+
expect(response).to have_http_status(:ok)
157+
expect(response.parsed_body['results'].first['name']).to eq('test server')
158+
expect(response.parsed_body['results'].first['uri']).to eq('bar://quax')
159+
expect(response.parsed_body['results'].first['uri_prefix']).to eq('bar')
160+
end
161+
162+
it 'create new nfs pxe server without authentication' do
163+
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
164+
post(url, :params => {:name => 'test server', :uri => 'nfs://quax'})
165+
expect(response).to have_http_status(:ok)
166+
expect(response.parsed_body['results'].first['name']).to eq('test server')
167+
expect(response.parsed_body['results'].first['uri']).to eq('nfs://quax')
168+
expect(response.parsed_body['results'].first['uri_prefix']).to eq('nfs')
169+
end
170+
171+
it 'create new pxe server with pxe menu' do
172+
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
173+
post(url, :params => {:name => 'foo', :uri => 'bar://quax',
174+
:pxe_menus => [{:file_name => 'menu_1'}, {:file_name => 'menu_2'}],
175+
:authentication => {:userid => 'foo', :password => 'bar' }})
176+
expect(response).to have_http_status(:ok)
177+
expect(PxeServer.find(response.parsed_body['results'].first['id']).pxe_menus.first[:file_name]).to eq('menu_1')
178+
end
179+
180+
it 'fail to create new non nfs pxe server without correct authentication' do
181+
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
182+
post(url, :params => {:name => 'test server', :uri => 'smb://quax', :authentication => {:userid => 'user'}})
183+
expect(response).to have_http_status(:bad_request)
184+
end
185+
186+
it 'will forbid create action withouth an appropriate authorization' do
187+
api_basic_authorize
188+
post(url, :params => {:name => 'foo', :uri => 'bar/quax',
189+
:pxe_menus => [{:file_name => 'menu_1'}, {:file_name => 'menu_2'}],
190+
:authentication => {:userid => 'foo', :password => 'bar' }})
191+
expect(response).to have_http_status(:forbidden)
192+
end
193+
end
194+
195+
describe 'update /api/pxe_servers/:id' do
196+
let(:url) { "/api/pxe_servers/#{pxe_server.id}" }
197+
198+
it 'update pxe server' do
199+
api_basic_authorize collection_action_identifier(:pxe_servers, :edit, :patch)
200+
patch(url, :params => {:name => 'updated name', :uri => 'updated://url', :pxe_menus => [{:file_name => 'updated menu'}]})
201+
expect(response).to have_http_status(:ok)
202+
expect(response.parsed_body['name']).to eq('updated name')
203+
expect(response.parsed_body['uri']).to eq('updated://url')
204+
expect(PxeServer.find(response.parsed_body['id']).pxe_menus.first[:file_name]).to eq('updated menu')
205+
end
206+
207+
it 'will forbid update action withouth an appropriate authorization' do
208+
api_basic_authorize
209+
patch(url, :params => {:name => 'updated name', :uri => 'updated://url', :pxe_menus => [{:file_name => 'updated menu'}]})
210+
expect(response).to have_http_status(:forbidden)
211+
end
212+
end
213+
214+
describe 'delete /api/pxe_servers/:id' do
215+
let(:url) { "/api/pxe_servers/#{pxe_server.id}" }
216+
217+
it 'delete pxe server' do
218+
api_basic_authorize collection_action_identifier(:pxe_servers, :delete, :delete)
219+
delete(url)
220+
expect(response).to have_http_status(:no_content)
221+
expect(PxeServer.exists?(pxe_server.id)).to be_falsey
222+
end
223+
224+
it 'will forbid delete action withouth an appropriate authorization' do
225+
api_basic_authorize
226+
delete(url)
227+
expect(response).to have_http_status(:forbidden)
228+
end
229+
end
93230
end

0 commit comments

Comments
 (0)