Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/controllers/api/pxe_menus_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Api
class PxeMenusController < BaseController
end
end
73 changes: 73 additions & 0 deletions app/controllers/api/pxe_servers_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,78 @@
module Api
class PxeServersController < BaseController
include Subcollections::PxeImages
include Subcollections::PxeMenus
INVALID_ATTRIBUTES = {
"PxeServer" => %w[id href], # Cannot update or create these
}.freeze
PXE_ATTRIBUTES = {
"PxeServer" => %w[name uri],
"PxeMenu" => %w[file_name],
"Authentication" => %w[userid password]
}.freeze

def create_resource(_type, _id, data = {})
authentication = data.delete('authentication')
menus = data.delete('pxe_menus')
validate_data_for('PxeServer', data)

PxeServer.transaction do
server = collection_class(:pxe_servers).new(data)
# generates uir_prefix which checks if server needs authentication or not
server.verify_uri_prefix_before_save

if server.requires_credentials? && server.missing_credentials?
validate_data_for('Authentication', authentication || {})
server.update_authentication({:default => authentication.compact}, {:save => true})
end

server.pxe_menus = create_pxe_menus(menus) if menus

if server.invalid?
raise BadRequestError, "Failed to add a pxe server - #{server.errors.full_messages.join(', ')}"
end

server.save
server
end
end

def delete_resource(_type, id = nil, data = nil)
raise BadRequestError, "Must specify an id for deleting a pxe server" unless id

super
end

def edit_resource(type, id, data)
server = resource_search(id, type, collection_class(:pxe_servers))
menus = data.delete('pxe_menus')
authentication = data.delete('authentication')
PxeServer.transaction do
if menus
server.pxe_menus.clear
data['pxe_menus'] = create_pxe_menus(menus)
end
server.update!(data)
server.update_authentication({:default => authentication.transform_keys(&:to_sym)}, {:save => true}) if authentication && server.requires_credentials?
server
end
end

private

def create_pxe_menus(menus)
menus.each do |menu|
validate_data_for('PxeMenu', menu)
end
menus.map do |menu|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should work also

collection_class(:pxe_menus).create(menu)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this case, what about to put line ^ on places where create_pxe_menus is called and put validation just before it ?

if menus
  server.pxe_menus.clear
  menus.each{|menu| validate_data_for(collection_class(:pxe_menus), menu) }
  data['pxe_menus'] = collection_class(:pxe_menus).create(menu)
end

collection_class(:pxe_menus).create(menu)
end
end

def validate_data_for(klass, data)
bad_attrs = []
PXE_ATTRIBUTES[klass].each { |attr| bad_attrs << attr if data[attr].blank? }
raise BadRequestError, "Missing attribute(s) #{bad_attrs.join(', ')} for creating a #{klass}" if bad_attrs.present?
end
end
end
9 changes: 9 additions & 0 deletions app/controllers/api/subcollections/pxe_menus.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Api
module Subcollections
module PxeMenus
def pxe_menus_query_resource(object)
object.pxe_menus
end
end
end
end
50 changes: 49 additions & 1 deletion config/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2381,23 +2381,71 @@
:get:
- :name: read
:identifier: pxe_server_view
:pxe_menus:
:description: PXE Menus
:identifier: pxe_server_accord
:options:
- :collection
:verbs: *gpppd
:klass: PxeMenu
:collection_actions:
:get:
- :name: read
:identifier: pxe_server_view
:post:
- :name: create
:identifier: pxe_server_create
:subresource_actions:
:get:
- :name: read
:identifier: pxe_server_view
:subcollection_actions:
:get:
- :name: read
:identifier: pxe_server_view
:post:
- :name: create
:identifier: pxe_server_create
:pxe_servers:
:description: PXE Servers
:identifier: pxe_server_accord
:options:
- :collection
:verbs: *g
:verbs: *gpppd
:klass: PxeServer
:subcollections:
- :pxe_images
- :pxe_menus
:collection_actions:
:post:
- :name: create
:identifier: pxe_server_create
- :name: edit
:identifier: pxe_server_edit
:patch:
- :name: edit
:identifier: pxe_server_edit
:delete:
- :name: delete
:identifier: pxe_server_delete
:get:
- :name: read
:identifier: pxe_server_view
:resource_actions:
:get:
- :name: read
:identifier: pxe_server_view
:patch:
- :name: edit
:identifier: pxe_server_edit
:post:
- :name: create
:identifier: pxe_server_create
- :name: edit
:identifier: pxe_server_edit
:delete:
- :name: delete
:identifier: pxe_server_delete
:quotas:
:description: TenantQuotas
:options:
Expand Down
139 changes: 138 additions & 1 deletion spec/requests/pxe_servers_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
RSpec.describe 'PxeServers API' do
let!(:pxe_server) { FactoryBot.create(:pxe_server) }
let(:pxe_server) { FactoryBot.build(:pxe_server).tap { |x| x.update_authentication(:default => {:userid => 'foo', :password => 'bar'}) } }
let!(:pxe_image_1) { FactoryBot.create(:pxe_image, :pxe_server => pxe_server) }
let!(:pxe_image_2) { FactoryBot.create(:pxe_image, :pxe_server => pxe_server) }
let!(:pxe_menu_1) { FactoryBot.create(:pxe_menu, :pxe_server => pxe_server) }

describe 'GET /api/pxe_servers' do
let(:url) { api_pxe_servers_url }
Expand Down Expand Up @@ -90,4 +91,140 @@
expect(response).to have_http_status(:forbidden)
end
end

describe 'GET /api/pxe_servers/:id/pxe_menus' do
let(:url) { "/api/pxe_servers/#{pxe_server.id}/pxe_menus" }

it 'lists all pxe menus of a pxe server' do
api_basic_authorize subcollection_action_identifier(:pxe_servers, :pxe_menus, :read, :get)
get(url)
expect_result_resources_to_include_hrefs(
"resources",
[
api_pxe_server_pxe_menu_url(nil, pxe_server, pxe_menu_1)
]
)
expect(response).to have_http_status(:ok)
end

it 'forbids access without an appropriate role' do
api_basic_authorize
get(url)
expect(response).to have_http_status(:forbidden)
end
end

describe 'GET /api/pxe_servers/:id/pxe_menus/:id' do
let(:url) { "/api/pxe_servers/#{pxe_server.id}/pxe_menus/#{pxe_menu_1.id}" }

it "will show a single pxe menu of a pxe server" do
api_basic_authorize subcollection_action_identifier(:pxe_servers, :pxe_images, :read, :get)
get(url)
expect_result_to_match_hash(
response.parsed_body,
"href" => api_pxe_server_pxe_menu_url(nil, pxe_server, pxe_menu_1),
"id" => pxe_menu_1.id.to_s,
"pxe_server_id" => pxe_server.id.to_s,
"file_name" => pxe_menu_1.file_name
)
expect(response).to have_http_status(:ok)
end

it 'forbids access without an appropriate role' do
api_basic_authorize
get(url)
expect(response).to have_http_status(:forbidden)
end
end

describe 'POST /api/pxe_servers/' do
let(:url) { "/api/pxe_servers/" }

it 'create new pxe server' do
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
post(
url,
:params => {
:name => 'test server',
:uri => 'bar://quax',
:authentication => {
:userid => 'foo',
:password => 'bar'
}
}
)
expect(response).to have_http_status(:ok)
expect(response.parsed_body['results'].first['name']).to eq('test server')
expect(response.parsed_body['results'].first['uri']).to eq('bar://quax')
expect(response.parsed_body['results'].first['uri_prefix']).to eq('bar')
end

it 'create new nfs pxe server without authentication' do
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
post(url, :params => {:name => 'test server', :uri => 'nfs://quax'})
expect(response).to have_http_status(:ok)
expect(response.parsed_body['results'].first['name']).to eq('test server')
expect(response.parsed_body['results'].first['uri']).to eq('nfs://quax')
expect(response.parsed_body['results'].first['uri_prefix']).to eq('nfs')
end

it 'create new pxe server with pxe menu' do
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
post(url, :params => {:name => 'foo', :uri => 'bar://quax',
:pxe_menus => [{:file_name => 'menu_1'}, {:file_name => 'menu_2'}],
:authentication => {:userid => 'foo', :password => 'bar' }})
expect(response).to have_http_status(:ok)
expect(PxeServer.find(response.parsed_body['results'].first['id']).pxe_menus.first[:file_name]).to eq('menu_1')
end

it 'fail to create new non nfs pxe server without correct authentication' do
api_basic_authorize collection_action_identifier(:pxe_servers, :create, :post)
post(url, :params => {:name => 'test server', :uri => 'smb://quax', :authentication => {:userid => 'user'}})
expect(response).to have_http_status(:bad_request)
end

it 'will forbid create action withouth an appropriate authorization' do
api_basic_authorize
post(url, :params => {:name => 'foo', :uri => 'bar/quax',
:pxe_menus => [{:file_name => 'menu_1'}, {:file_name => 'menu_2'}],
:authentication => {:userid => 'foo', :password => 'bar' }})
expect(response).to have_http_status(:forbidden)
end
end

describe 'update /api/pxe_servers/:id' do
let(:url) { "/api/pxe_servers/#{pxe_server.id}" }

it 'update pxe server' do
api_basic_authorize collection_action_identifier(:pxe_servers, :edit, :patch)
patch(url, :params => {:name => 'updated name', :uri => 'updated://url', :pxe_menus => [{:file_name => 'updated menu'}]})
expect(response).to have_http_status(:ok)
expect(response.parsed_body['name']).to eq('updated name')
expect(response.parsed_body['uri']).to eq('updated://url')
expect(PxeServer.find(response.parsed_body['id']).pxe_menus.first[:file_name]).to eq('updated menu')
end

it 'will forbid update action withouth an appropriate authorization' do
api_basic_authorize
patch(url, :params => {:name => 'updated name', :uri => 'updated://url', :pxe_menus => [{:file_name => 'updated menu'}]})
expect(response).to have_http_status(:forbidden)
end
end

describe 'delete /api/pxe_servers/:id' do
let(:url) { "/api/pxe_servers/#{pxe_server.id}" }

it 'delete pxe server' do
api_basic_authorize collection_action_identifier(:pxe_servers, :delete, :delete)
delete(url)
expect(response).to have_http_status(:no_content)
expect(PxeServer.exists?(pxe_server.id)).to be_falsey
end

it 'will forbid delete action withouth an appropriate authorization' do
api_basic_authorize
delete(url)
expect(response).to have_http_status(:forbidden)
end
end
end