diff --git a/app/controllers/api/physical_servers_controller.rb b/app/controllers/api/physical_servers_controller.rb new file mode 100644 index 00000000000..fcadd131e16 --- /dev/null +++ b/app/controllers/api/physical_servers_controller.rb @@ -0,0 +1,49 @@ +module Api + class PhysicalServersController < BaseController + def blink_loc_led_resource(type, id, _data) + change_resource_state(:blink_loc_led, type, id) + end + + def turn_on_loc_led_resource(type, id, _data) + change_resource_state(:turn_on_loc_led, type, id) + end + + def turn_off_loc_led_resource(type, id, _data) + change_resource_state(:turn_off_loc_led, type, id) + end + + def power_on_resource(type, id, _data) + change_resource_state(:power_on, type, id) + end + + def power_off_resource(type, id, _data) + change_resource_state(:power_off, type, id) + end + + def restart_resource(type, id, _data) + change_resource_state(:restart, type, id) + end + + private + + def change_resource_state(state, type, id) + raise BadRequestError, "Must specify an id for changing a #{type} resource" unless id + + api_action(type, id) do |klass| + begin + server = resource_search(id, type, klass) + desc = "Requested server state #{state} for #{server_ident(server)}" + api_log_info(desc) + task_id = queue_object_action(server, desc, :method_name => state, :role => :ems_operations) + action_result(true, desc, :task_id => task_id) + rescue => err + action_result(false, err.to_s) + end + end + end + + def server_ident(server) + "Server instance: #{server.id} name:'#{server.name}'" + end + end +end diff --git a/app/models/physical_server.rb b/app/models/physical_server.rb index 66a4d5e43f6..d480c9ebfd2 100644 --- a/app/models/physical_server.rb +++ b/app/models/physical_server.rb @@ -1,6 +1,7 @@ class PhysicalServer < ApplicationRecord include NewWithTypeStiMixin include MiqPolicyMixin + include_concern 'Operations' acts_as_miq_taggable @@ -32,4 +33,31 @@ def has_compliance_policies? def label_for_vendor VENDOR_TYPES[vendor] end + + def is_refreshable? + refreshable_status[:show] + end + + def is_refreshable_now? + refreshable_status[:enabled] + end + + def is_refreshable_now_error_message + refreshable_status[:message] + end + + def is_available?(_address) + # TODO: (walteraa) remove bypass + true + end + + def smart? + # TODO: (walteraa) remove bypass + true + end + + def my_zone + ems = ext_management_system + ems ? ems.my_zone : MiqServer.my_zone + end end diff --git a/app/models/physical_server/operations.rb b/app/models/physical_server/operations.rb new file mode 100644 index 00000000000..169c4e964a1 --- /dev/null +++ b/app/models/physical_server/operations.rb @@ -0,0 +1,6 @@ +module PhysicalServer::Operations + extend ActiveSupport::Concern + + include_concern 'Power' + include_concern 'Led' +end diff --git a/app/models/physical_server/operations/led.rb b/app/models/physical_server/operations/led.rb new file mode 100644 index 00000000000..d67e05c669b --- /dev/null +++ b/app/models/physical_server/operations/led.rb @@ -0,0 +1,27 @@ +module PhysicalServer::Operations::Led + def blink_loc_led + change_state(:blink_loc_led) + end + + def turn_on_loc_led + change_state(:turn_on_loc_led) + end + + def turn_off_loc_led + change_state(:turn_off_loc_led) + end + + private + + def change_state(verb) + unless ext_management_system + raise _("A Server #{self} <%{name}> with Id: <%{id}> is not associated \ +with a provider.") % {:name => name, :id => id} + end + + options = {:uuid => ems_ref} + _log.info("Begin #{verb} server: #{name} with UUID: #{ems_ref}") + ext_management_system.send(verb, self, options) + _log.info("Complete #{verb} #{self}") + end +end diff --git a/app/models/physical_server/operations/power.rb b/app/models/physical_server/operations/power.rb new file mode 100644 index 00000000000..7bdc86712e7 --- /dev/null +++ b/app/models/physical_server/operations/power.rb @@ -0,0 +1,26 @@ +module PhysicalServer::Operations::Power + def power_on + change_state(:power_on) + end + + def power_off + change_state(:power_off) + end + + def restart + change_state(:restart) + end + + private + + def change_state(verb) + unless ext_management_system + raise _(" A Server #{self} <%{name}> with Id: <%{id}> + is not associated with a provider.") % {:name => name, :id => id} + end + options = {:uuid => ems_ref} + _log.info("Begin #{verb} server: #{name} with UUID: #{ems_ref}") + ext_management_system.send(verb, self, options) + _log.info("Complete #{verb} #{self}") + end +end diff --git a/config/api.yml b/config/api.yml index 0b3d9b32634..f83bdeb7da6 100644 --- a/config/api.yml +++ b/config/api.yml @@ -689,6 +689,7 @@ :description: Firmwares :options: - :collection + - :subcollection :verbs: *gp :klass: Firmware :identifier: firmware @@ -1025,6 +1026,50 @@ :delete: - :name: delete :identifier: orchestration_template_remove + :physical_servers: + :description: Physical Servers + :identifier: physical_server + :options: + - :collection + :verbs: *gp + :klass: PhysicalServer + :subcollections: + :collection_actions: + :get: + - :name: read + :identifier: physical_server_show_list + :post: + - :name: query + :identifier: physical_server_show_list + - :name: power_on + :identifier: physical_server_power_on + - :name: power_off + :identifier: physical_server_power_off + - :name: restart + :identifier: physical_server_restart + - :name: blink_loc_led + :identifier: physical_server_blink_loc_led + - :name: turn_on_loc_led + :identifier: physical_server_turn_on_loc_led + - :name: turn_off_loc_led + :identifier: physical_server_turn_off_loc_led + :resource_actions: + :get: + - :name: read + :identifier: physical_server_show + :post: + - :name: power_on + :identifier: physical_server_power_on + - :name: power_off + :identifier: physical_server_power_off + - :name: restart + :identifier: physical_server_restart + - :name: blink_loc_led + :identifier: physical_server_blink_loc_led + - :name: turn_on_loc_led + :identifier: physical_server_turn_on_loc_led + - :name: turn_off_loc_led + :identifier: physical_server_turn_off_loc_led :pictures: :description: Pictures :options: diff --git a/spec/factories/physical_server.rb b/spec/factories/physical_server.rb new file mode 100644 index 00000000000..0f48c59aee8 --- /dev/null +++ b/spec/factories/physical_server.rb @@ -0,0 +1,4 @@ +FactoryGirl.define do + factory :physical_server do + end +end diff --git a/spec/requests/api/collections_spec.rb b/spec/requests/api/collections_spec.rb index 3e2e7bd0006..08f28566254 100644 --- a/spec/requests/api/collections_spec.rb +++ b/spec/requests/api/collections_spec.rb @@ -308,6 +308,11 @@ def test_collection_bulk_query(collection, collection_url, klass, id = nil) FactoryGirl.create(:firmware) test_collection_query(:firmwares, firmwares_url, Firmware) end + + it 'query PhysicalServers' do + FactoryGirl.create(:physical_server) + test_collection_query(:physical_servers, physical_servers_url, PhysicalServer) + end end context "Collections Bulk Queries" do @@ -568,5 +573,10 @@ def test_collection_bulk_query(collection, collection_url, klass, id = nil) FactoryGirl.create(:firmware) test_collection_bulk_query(:firmwares, firmwares_url, Firmware) end + + it 'bulk query PhysicalServers' do + FactoryGirl.create(:physical_server) + test_collection_bulk_query(:physical_servers, physical_servers_url, PhysicalServer) + end end end diff --git a/spec/requests/api/physical_servers_spec.rb b/spec/requests/api/physical_servers_spec.rb new file mode 100644 index 00000000000..71a13110487 --- /dev/null +++ b/spec/requests/api/physical_servers_spec.rb @@ -0,0 +1,134 @@ +RSpec.describe "physical_servers API" do + describe "display a physical server's details" do + context "with valid properties" do + it "shows all of its properties" do + ps = FactoryGirl.create(:physical_server, :ems_ref => "A59D5B36821111E1A9F5E41F13ED4F6A") + + api_basic_authorize action_identifier(:physical_servers, :read, :resource_actions, :get) + run_get physical_servers_url(ps.id) + + expect_single_resource_query("ems_ref" => "A59D5B36821111E1A9F5E41F13ED4F6A") + end + end + end + + describe "power on/off a physical server" do + context "with valid action names" do + it "powers on a server successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :power_on, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:power_on)) + + expect(response).to have_http_status(:success) + end + + it "powers off a server successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :power_off, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:power_off)) + + expect(response).to have_http_status(:success) + end + + it "restarts a server successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :restart, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:restart)) + + expect(response).to have_http_status(:success) + end + end + + context "without an appropriate role" do + it "fails to power on a server" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:power_on)) + + expect(response).to have_http_status(:forbidden) + end + + it "fails to power off a server" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:power_off)) + + expect(response).to have_http_status(:forbidden) + end + + it "fails to restart a server" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:restart)) + + expect(response).to have_http_status(:forbidden) + end + end + end + + describe "turn on/off a physical server's location LED" do + context "with valid action names" do + it "turns on a location LED successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :turn_on_loc_led, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:turn_on_loc_led)) + + expect(response).to have_http_status(:success) + end + + it "turns off a location LED successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :turn_off_loc_led, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:turn_off_loc_led)) + + expect(response).to have_http_status(:success) + end + + it "blinks a location LED successfully" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize action_identifier(:physical_servers, :blink_loc_led, :resource_actions, :post) + run_post(physical_servers_url(ps.id), gen_request(:blink_loc_led)) + + expect(response).to have_http_status(:success) + end + end + + context "without an appropriate role" do + it "fails to turn on a location LED" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:turn_on_loc_led)) + + expect(response).to have_http_status(:forbidden) + end + + it "fails to turn off a location LED" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:turn_off_loc_led)) + + expect(response).to have_http_status(:forbidden) + end + + it "fails to blink a location LED" do + ps = FactoryGirl.create(:physical_server) + + api_basic_authorize + run_post(physical_servers_url(ps.id), gen_request(:blink_loc_led)) + + expect(response).to have_http_status(:forbidden) + end + end + end +end