From 96541729fb1b3b2d87a68b483e30fadac24d4bcb Mon Sep 17 00:00:00 2001 From: Samuel Beaulieu Date: Thu, 19 Oct 2017 17:25:15 -0500 Subject: [PATCH] (POOLER-93) Extend API endpoint to provide just what is needed The status endpoint provides a lot of statistics. This commit extends it by supporting a query parameter called 'view' which may contain one or multiple comma separated names for the top-level statistics returned in the JSON response. status is always returned. Optional elements are capacity,queue,clone,boot,pools Everything is returned when 'view' is not specified, which is backwards compatible with the current behavior. --- lib/vmpooler/api/v1.rb | 22 +++++-- spec/integration/api/v1/status_spec.rb | 80 ++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/lib/vmpooler/api/v1.rb b/lib/vmpooler/api/v1.rb index 6ceb5c3..c397b7c 100644 --- a/lib/vmpooler/api/v1.rb +++ b/lib/vmpooler/api/v1.rb @@ -176,23 +176,33 @@ module Vmpooler # ], # "uptime": 179585.9 # } + # + # If the query parameter 'view' is provided, it will be used to select which top level + # element to compute and return. Select them by specifying them in a comma separated list. + # For example /status?view=capacity,boot + # would return only the "capacity" and "boot" statistics. "status" is always returned + get "#{api_prefix}/status/?" do content_type :json + if params[:view] + views = params[:view].split(",") + end + result = { - pools: {}, status: { ok: true, message: 'Battle station fully armed and operational.' } } - result[:capacity] = get_capacity_metrics(pools, backend) - result[:queue] = get_queue_metrics(pools, backend) - result[:clone] = get_task_metrics(backend, 'clone', Date.today.to_s) - result[:boot] = get_task_metrics(backend, 'boot', Date.today.to_s) + result[:capacity] = get_capacity_metrics(pools, backend) unless views and not views.include?("capacity") + result[:queue] = get_queue_metrics(pools, backend) unless views and not views.include?("queue") + result[:clone] = get_task_metrics(backend, 'clone', Date.today.to_s) unless views and not views.include?("clone") + result[:boot] = get_task_metrics(backend, 'boot', Date.today.to_s) unless views and not views.include?("boot") # Check for empty pools + result[:pools] = {} unless views and not views.include?("pools") pools.each do |pool| # REMIND: move this out of the API and into the back-end ready = backend.scard('vmpooler__ready__' + pool['name']).to_i @@ -220,7 +230,7 @@ module Vmpooler result[:status][:ok] = false result[:status][:message] = "Found #{result[:status][:empty].length} empty pools." end - end + end unless views and not views.include?("pools") result[:status][:uptime] = (Time.now - Vmpooler::API.settings.config[:uptime]).round(1) if Vmpooler::API.settings.config[:uptime] diff --git a/spec/integration/api/v1/status_spec.rb b/spec/integration/api/v1/status_spec.rb index 96b54f1..2f2f1ba 100644 --- a/spec/integration/api/v1/status_spec.rb +++ b/spec/integration/api/v1/status_spec.rb @@ -118,5 +118,85 @@ describe Vmpooler::API::V1 do expect(result["status"]["empty"].sort).to eq(["pool1", "pool2", "pool3"]) end end + describe 'GET /status with view query parameter' do + it 'returns capacity when specified' do + get "#{prefix}/status?view=capacity" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to_not be(nil) + expect(result["queue"]).to be(nil) + expect(result["clone"]).to be(nil) + expect(result["boot"]).to be(nil) + expect(result["pools"]).to be(nil) + expect(result["status"]).to_not be(nil) + end + it 'returns pools and queue when specified' do + get "#{prefix}/status?view=pools,queue" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to be(nil) + expect(result["queue"]).to_not be(nil) + expect(result["clone"]).to be(nil) + expect(result["boot"]).to be(nil) + expect(result["pools"]).to_not be(nil) + expect(result["status"]).to_not be(nil) + end + it 'does nothing with invalid view names' do + get "#{prefix}/status?view=clone,boot,invalidThingToView" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to be(nil) + expect(result["queue"]).to be(nil) + expect(result["clone"]).to_not be(nil) + expect(result["boot"]).to_not be(nil) + expect(result["pools"]).to be(nil) + expect(result["status"]).to_not be(nil) + end + it 'returns everything when view is not specified' do + get "#{prefix}/status" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to_not be(nil) + expect(result["queue"]).to_not be(nil) + expect(result["clone"]).to_not be(nil) + expect(result["boot"]).to_not be(nil) + expect(result["pools"]).to_not be(nil) + expect(result["status"]).to_not be(nil) + end + it 'returns everything when view is alone' do + get "#{prefix}/status?view" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to_not be(nil) + expect(result["queue"]).to_not be(nil) + expect(result["clone"]).to_not be(nil) + expect(result["boot"]).to_not be(nil) + expect(result["pools"]).to_not be(nil) + expect(result["status"]).to_not be(nil) + end + it 'returns status only when view is empty' do + get "#{prefix}/status?view=" + + # of course /status doesn't conform to the weird standard everything else uses... + expect(last_response.header['Content-Type']).to eq('application/json') + result = JSON.parse(last_response.body) + expect(result["capacity"]).to be(nil) + expect(result["queue"]).to be(nil) + expect(result["clone"]).to be(nil) + expect(result["boot"]).to be(nil) + expect(result["pools"]).to be(nil) + expect(result["status"]).to_not be(nil) + end + end end end