diff --git a/app/controllers/api/services_controller.rb b/app/controllers/api/services_controller.rb index 27e7e4c00bb..3b25a1f9923 100644 --- a/app/controllers/api/services_controller.rb +++ b/app/controllers/api/services_controller.rb @@ -18,6 +18,25 @@ def edit_resource(type, id, data) super(type, id, attributes) end + def add_resource_resource(type, id, data) + raise "Must specify a service href or id to add_resource to" unless id + svc = resource_search(id, type, collection_class(type)) + + resource_href = data.fetch_path("resource", "href") + raise "Must specify a resource reference" unless resource_href + + resource_type, resource_id = parse_href(resource_href) + raise "Invalid resource href specified #{resource_href}" unless resource_type && resource_id + + resource = resource_search(resource_id, resource_type, collection_class(resource_type)) + raise "Cannot assign #{resource_type} to #{service_ident(svc)}" unless resource.respond_to? :add_to_service + + resource.add_to_service(svc) + action_result(true, "Assigned resource #{resource_type} id:#{resource_id} to #{service_ident(svc)}") + rescue => err + action_result(false, err.to_s) + end + def reconfigure_resource(type, id = nil, data = nil) raise BadRequestError, "Must specify an id for Reconfiguring a #{type} resource" unless id diff --git a/config/api.yml b/config/api.yml index 111d76a87d3..8c65ed798b3 100644 --- a/config/api.yml +++ b/config/api.yml @@ -1911,6 +1911,8 @@ :identifier: service_tag - :name: unassign_tags :identifier: service_tag + - :name: add_resource + :identifier: service_edit :resource_actions: :get: - :name: read @@ -1934,6 +1936,8 @@ :identifier: service_admin - :name: delete :identifier: service_delete + - :name: add_resource + :identifier: service_edit :delete: - :name: delete :identifier: service_delete diff --git a/spec/requests/api/custom_actions_spec.rb b/spec/requests/api/custom_actions_spec.rb index e42d39a599c..1d9f1d9ac17 100644 --- a/spec/requests/api/custom_actions_spec.rb +++ b/spec/requests/api/custom_actions_spec.rb @@ -75,7 +75,7 @@ def expect_result_to_have_custom_actions_hash run_get services_url(svc1.id) expect_result_to_have_keys(%w(id href actions)) - expect(response.parsed_body["actions"].collect { |a| a["name"] }).to match_array(%w(edit)) + expect(response.parsed_body["actions"].collect { |a| a["name"] }).to match_array(%w(edit add_resource)) end end @@ -91,7 +91,7 @@ def expect_result_to_have_custom_actions_hash run_get services_url(svc1.id) expect_result_to_have_keys(%w(id href actions)) - expect(response.parsed_body["actions"].collect { |a| a["name"] }).to match_array(%w(edit button1 button2 button3)) + expect(response.parsed_body["actions"].collect { |a| a["name"] }).to match_array(%w(edit button1 button2 button3 add_resource)) end it "supports the custom_actions attribute" do diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index 89cded552d7..1aae8105600 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -667,4 +667,129 @@ def expect_svc_with_vms expect(response).to have_http_status(:forbidden) end end + + describe 'add_resource' do + let(:vm1) { FactoryGirl.create(:vm_vmware) } + let(:vm2) { FactoryGirl.create(:vm_vmware) } + + it 'can add vm to services by href with an appropriate role' do + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resources' => [ + { 'href' => services_url(svc.id), 'resource' => {'href' => vms_url(vm1.id)} }, + { 'href' => services_url(svc1.id), 'resource' => {'href' => vms_url(vm2.id)} } + ] + } + + run_post(services_url, request) + + expected = { + 'results' => [ + { 'success' => true, 'message' => "Assigned resource vms id:#{vm1.id} to Service id:#{svc.id} name:'#{svc.name}'"}, + { 'success' => true, 'message' => "Assigned resource vms id:#{vm2.id} to Service id:#{svc1.id} name:'#{svc1.name}'"} + ] + } + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + expect(svc.reload.vms).to eq([vm1]) + expect(svc1.reload.vms).to eq([vm2]) + end + + it 'returns individual success and failures' do + user = FactoryGirl.create(:user) + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resources' => [ + { 'href' => services_url(svc.id), 'resource' => {'href' => vms_url(vm1.id)} }, + { 'href' => services_url(svc1.id), 'resource' => {'href' => users_url(user.id)} } + ] + } + + run_post(services_url, request) + + expected = { + 'results' => [ + { 'success' => true, 'message' => "Assigned resource vms id:#{vm1.id} to Service id:#{svc.id} name:'#{svc.name}'"}, + { 'success' => false, 'message' => "Cannot assign users to Service id:#{svc1.id} name:'#{svc1.name}'"} + ] + } + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + expect(svc.reload.vms).to eq([vm1]) + end + + it 'requires a valid resource' do + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resource' => { 'resource' => { 'href' => '1' } } + } + + run_post(services_url(svc.id), request) + + expected = { 'success' => false, 'message' => "Invalid resource href specified 1"} + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + end + + it 'requires the resource to respond to add_to_service' do + user = FactoryGirl.create(:user) + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resource' => { 'resource' => { 'href' => users_url(user.id) } } + } + + run_post(services_url(svc.id), request) + + expected = { 'success' => false, 'message' => "Cannot assign users to Service id:#{svc.id} name:'#{svc.name}'"} + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + end + + it 'requires a resource reference' do + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resource' => { 'resource' => {} } + } + + run_post(services_url(svc.id), request) + + expected = { 'success' => false, 'message' => "Must specify a resource reference"} + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + end + + it 'can add a vm to a resource with appropriate role' do + api_basic_authorize(collection_action_identifier(:services, :add_resource)) + request = { + 'action' => 'add_resource', + 'resource' => { 'resource' => {'href' => vms_url(vm1.id)} } + } + + run_post(services_url(svc.id), request) + + expected = { 'success' => true, 'message' => "Assigned resource vms id:#{vm1.id} to Service id:#{svc.id} name:'#{svc.name}'"} + + expect(response).to have_http_status(:ok) + expect(response.parsed_body).to eq(expected) + expect(svc.reload.vms).to eq([vm1]) + end + + it 'cannot add multiple vms to multiple services by href without an appropriate role' do + api_basic_authorize + + run_post(services_url, 'action' => 'add_resource') + + expect(response).to have_http_status(:forbidden) + end + end end