diff --git a/src/onegate/onegate-server.rb b/src/onegate/onegate-server.rb index d45159abbd..89067bda55 100644 --- a/src/onegate/onegate-server.rb +++ b/src/onegate/onegate-server.rb @@ -137,6 +137,20 @@ helpers do service.body end + + def parse_json(json_str, root_element) + begin + hash = JSON.parse(json_str) + rescue Exception => e + return OpenNebula::Error.new(e.message) + end + + if hash.has_key?(root_element) + return hash[root_element] + else + return OpenNebula::Error.new("Error parsing JSON: Wrong resource type") + end + end end NIC_VALID_KEYS = %w(IP IP6_LINK IP6_SITE IP6_GLOBAL NETWORK MAC) @@ -155,6 +169,8 @@ def build_vm_hash(vm_hash) "VM" => { "NAME" => vm_hash["NAME"], "ID" => vm_hash["ID"], + "STATE" => vm_hash["STATE"], + "LCM_STATE" => vm_hash["LCM_STATE"], "USER_TEMPLATE" => Hash[vm_hash["USER_TEMPLATE"].select {|k,v| !USER_TEMPLATE_INVALID_KEYS.include?(k) }], @@ -175,6 +191,7 @@ def build_service_hash(service_hash) service_info = { "name" => service_hash["DOCUMENT"]["NAME"], "id" => service_hash["DOCUMENT"]["ID"], + "state" => service_hash["DOCUMENT"]["TEMPLATE"]["BODY"]["state"], "roles" => [] } @@ -294,11 +311,184 @@ get '/service' do [200, response.to_json] end +get '/vms/:id' do + client = authenticate(request.env, params) + + halt 401, "Not authorized" if client.nil? + + source_vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i + requested_vm_id = params[:id].to_i + + vm = get_vm(source_vm_id, client) + + service_id = vm['USER_TEMPLATE/SERVICE_ID'] + service = get_service(service_id, client) + + service_hash = JSON.parse(service) + + response = build_service_hash(service_hash) rescue nil + + if response.nil? + error_msg = "VMID:#{source_vm_id} Service #{service_id} is empty." + logger.error {error_msg} + halt 400, error_msg + end + + # Check that the user has not spoofed the Service_ID + service_vm_ids = response["SERVICE"]["roles"].collect do |r| + r["nodes"].collect{|n| n["deploy_id"]} + end.flatten rescue [] + + if service_vm_ids.empty? || !service_vm_ids.include?(requested_vm_id) + error_msg = "VMID:#{requested_vm_id} Service #{service_id} does not contain VM." + logger.error {error_msg} + halt 400, error_msg + end + + vm = get_vm(requested_vm_id, client) + + response = build_vm_hash(vm.to_hash["VM"]) + + [200, response.to_json] +end + +post '/vms/:id/action' do + client = authenticate(request.env, params) + + halt 401, "Not authorized" if client.nil? + + source_vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i + requested_vm_id = params[:id].to_i + + vm = get_vm(source_vm_id, client) + + service_id = vm['USER_TEMPLATE/SERVICE_ID'] + service = get_service(service_id, client) + + service_hash = JSON.parse(service) + + response = build_service_hash(service_hash) rescue nil + + if response.nil? + error_msg = "VMID:#{source_vm_id} Service #{service_id} is empty." + logger.error {error_msg} + halt 400, error_msg + end + + # Check that the user has not spoofed the Service_ID + service_vm_ids = response["SERVICE"]["roles"].collect do |r| + r["nodes"].collect{|n| n["deploy_id"]} + end.flatten rescue [] + + if service_vm_ids.empty? || !service_vm_ids.include?(requested_vm_id) + error_msg = "VMID:#{requested_vm_id} Service #{service_id} does not contain VM." + logger.error {error_msg} + halt 400, error_msg + end + + vm = get_vm(requested_vm_id, client) + + action_hash = parse_json(request.body.read, 'action') + if OpenNebula.is_error?(action_hash) + halt 400, rc.message + end + + rc = case action_hash['perform'] + when "deploy" then vm.deploy(action_hash['params']) + when "delete" then vm.finalize + when "hold" then vm.hold + when "livemigrate" then vm.migrate(action_hash['params'], true) + when "migrate" then vm.migrate(action_hash['params'], false) + when "resume" then vm.resume + when "release" then vm.release + when "stop" then vm.stop + when "suspend" then vm.suspend + when "saveas" then vm.save_as(action_hash['params']) + when "snapshot_create" then vm.snapshot_create(action_hash['params']) + when "snapshot_revert" then vm.snapshot_revert(action_hash['params']) + when "snapshot_delete" then vm.snapshot_delete(action_hash['params']) + when "shutdown" then vm.shutdown(action_hash['params']) + when "reboot" then vm.reboot(action_hash['params']) + when "poweroff" then vm.poweroff(action_hash['params']) + when "resubmit" then vm.resubmit + when "chown" then vm.chown(action_hash['params']) + when "chmod" then vm.chmod_octet(action_hash['params']) + when "resize" then vm.resize(action_hash['params']) + when "attachdisk" then vm.disk_attach(action_hash['params']) + when "detachdisk" then vm.disk_detach(action_hash['params']) + when "attachnic" then vm.nic_attach(action_hash['params']) + when "detachnic" then vm.nic_detach(action_hash['params']) + when "update" then vm.update(action_hash['params']) + when "rename" then vm.rename(action_hash['params']) + when "undeploy" then vm.undeploy(action_hash['params']) + when "resched" then vm.resched + when "unresched" then vm.unresched + when "recover" then vm.recover(action_hash['params']) + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + + if OpenNebula.is_error?(rc) + halt 500, rc.message + else + [204, vm.to_json] + end +end + +put '/service/role/:role' do + client = authenticate(request.env, params) + + halt 401, "Not authorized" if client.nil? + + vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i + + vm = get_vm(vm_id, client) + + service_id = vm['USER_TEMPLATE/SERVICE_ID'] + service = get_service(service_id, client) + + service_hash = JSON.parse(service) + + response = build_service_hash(service_hash) rescue nil + + if response.nil? + error_msg = "VMID:#{vm_id} Service #{service_id} is empty." + logger.error {error_msg} + halt 400, error_msg + end + + # Check that the user has not spoofed the Service_ID + service_vm_ids = response["SERVICE"]["roles"].collect do |r| + r["nodes"].collect{|n| n["deploy_id"]} + end.flatten rescue [] + + if service_vm_ids.empty? || !service_vm_ids.include?(vm_id) + error_msg = "VMID:#{vm_id} Service #{service_id} does not contain VM." + logger.error {error_msg} + halt 400, error_msg + end + + action_response = flow_client(client).put( + "/service/" + service_id + "/role/" + params[:role], + request.body.read) + + if CloudClient::is_error?(action_response) + error_msg = "Error performing action on service #{service_id} role #{params[:role]}" + logger.error {error_msg} + logger.error {action_response.message} + halt 400, error_msg + end + + [200, ""] +end + ############# # DEPRECATED ############# -put '/vm/:id' do +put '/vms/:id' do client = authenticate(request.env, params) halt 401, "Not authorized" if client.nil?