diff --git a/app/controllers/api/base_controller/parser.rb b/app/controllers/api/base_controller/parser.rb index ab3b4628d9f..b392badaeb9 100644 --- a/app/controllers/api/base_controller/parser.rb +++ b/app/controllers/api/base_controller/parser.rb @@ -291,7 +291,7 @@ def validate_post_api_action_as_subcollection(cname, mname, aname) return if cname == @req.collection return if collection_config.subcollection_denied?(@req.collection, cname) - aspec = collection_config.typed_subcollection_actions(@req.collection, cname) + aspec = collection_config.typed_subcollection_actions(@req.collection, cname, @req.s_id ? :subresource : :subcollection) return unless aspec action_hash = fetch_action_hash(aspec, mname, aname) diff --git a/app/controllers/api/subcollections/snapshots.rb b/app/controllers/api/subcollections/snapshots.rb index ac2c5591762..8fde24994bc 100644 --- a/app/controllers/api/subcollections/snapshots.rb +++ b/app/controllers/api/subcollections/snapshots.rb @@ -34,6 +34,17 @@ def delete_resource_snapshots(parent, type, id, _data) end alias snapshots_delete_resource delete_resource_snapshots + def snapshots_revert_resource(parent, type, id, _data) + raise parent.unsupported_reason(:revert_to_snapshot) unless parent.supports_revert_to_snapshot? + snapshot = resource_search(id, type, collection_class(type)) + + message = "Reverting to snapshot #{snapshot.name} for #{snapshot_ident(parent)}" + task_id = queue_object_action(parent, message, :method_name => "revert_to_snapshot", :args => [id]) + action_result(true, message, :task_id => task_id) + rescue => e + action_result(false, e.to_s) + end + private def snapshot_ident(parent) diff --git a/config/api.yml b/config/api.yml index 5e8b2d954fb..2d59609c870 100644 --- a/config/api.yml +++ b/config/api.yml @@ -2262,6 +2262,8 @@ - :name: read :identifier: vm_snapshot_view :post: + - :name: revert + :identifier: vm_snapshot_revert - :name: delete :identifier: vm_snapshot_delete :delete: diff --git a/spec/requests/api/snapshots_spec.rb b/spec/requests/api/snapshots_spec.rb index 13019ba3499..9ae43ae34dc 100644 --- a/spec/requests/api/snapshots_spec.rb +++ b/spec/requests/api/snapshots_spec.rb @@ -133,6 +133,52 @@ end end + describe "POST /api/vms/:c_id/snapshots/:s_id with revert action" do + it "can queue a VM for reverting to a snapshot" do + api_basic_authorize(action_identifier(:vms, :revert, :snapshots_subresource_actions)) + ems = FactoryGirl.create(:ext_management_system) + host = FactoryGirl.create(:host, :ext_management_system => ems) + vm = FactoryGirl.create(:vm_vmware, :name => "Alice's VM", :host => host, :ext_management_system => ems) + snapshot = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => vm) + + run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert") + + expected = { + "message" => "Reverting to snapshot Alice's snapshot for Virtual Machine id:#{vm.id} name:'Alice's VM'", + "success" => true, + "task_href" => a_string_matching(tasks_url), + "task_id" => anything + } + expect(response.parsed_body).to include(expected) + expect(response).to have_http_status(:ok) + end + + it "renders a failed action response if reverting is not supported" do + api_basic_authorize(action_identifier(:vms, :revert, :snapshots_subresource_actions)) + vm = FactoryGirl.create(:vm_vmware) + snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm) + + run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert") + + expected = { + "success" => false, + "message" => "The VM is not connected to a Host" + } + expect(response.parsed_body).to include(expected) + expect(response).to have_http_status(:ok) + end + + it "will not revert to a snapshot unless authorized" do + api_basic_authorize + vm = FactoryGirl.create(:vm_vmware) + snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm) + + run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert") + + expect(response).to have_http_status(:forbidden) + end + end + describe "POST /api/vms/:c_id/snapshots/:s_id with delete action" do it "can queue a snapshot for deletion" do api_basic_authorize(action_identifier(:vms, :delete, :snapshots_subresource_actions, :delete))