From 8746f21bb5c0511c52c86d8da6619c04b3f8d1f7 Mon Sep 17 00:00:00 2001 From: Julia Benais Date: Wed, 8 May 2019 17:56:01 -0400 Subject: [PATCH] Add support for dashboard list API v2 --- .rubocop.yml | 2 + lib/dogapi/facade.rb | 49 ++++++++++++++++++ lib/dogapi/v2.rb | 1 + lib/dogapi/v2/dashboard_list.rb | 68 +++++++++++++++++++++++++ spec/integration/dashboard_list_spec.rb | 46 ++++++++++++++++- spec/spec_helper.rb | 65 ++++++++++++++++++++++- 6 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 lib/dogapi/v2.rb create mode 100644 lib/dogapi/v2/dashboard_list.rb diff --git a/.rubocop.yml b/.rubocop.yml index 7b42b89b..e2f5e299 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,5 +11,7 @@ # URISchemes: http, https Metrics/LineLength: Max: 122 +Metrics/ModuleLength: + Max: 200 inherit_from: .rubocop_todo.yml diff --git a/lib/dogapi/facade.rb b/lib/dogapi/facade.rb index c25a8fa3..c5e412a7 100644 --- a/lib/dogapi/facade.rb +++ b/lib/dogapi/facade.rb @@ -1,8 +1,51 @@ require 'time' require 'dogapi/v1' +require 'dogapi/v2' module Dogapi + # A simple DogAPI client supporting the version 2. + # + # See Dogapi::V2 for the thick underlying clients + class ClientV2 + attr_accessor :datadog_host + def initialize(api_key, application_key=nil, host=nil, device=nil, silent=true, timeout=nil, endpoint=nil) + + if api_key + @api_key = api_key + else + raise 'Please provide an API key to submit your data' + end + + @application_key = application_key + @datadog_host = endpoint || Dogapi.find_datadog_host() + @host = host || Dogapi.find_localhost() + @device = device + + @dashboard_list_service_v2 = Dogapi::V2::DashboardListService.new( + @api_key, @application_key, silent, timeout, @datadog_host + ) + + end + + def add_items_to_dashboard_list(dashboard_list_id, dashboards) + @dashboard_list_service_v2.add_items(dashboard_list_id, dashboards) + end + + def update_items_of_dashboard_list(dashboard_list_id, dashboards) + @dashboard_list_service_v2.update_items(dashboard_list_id, dashboards) + end + + def delete_items_from_dashboard_list(dashboard_list_id, dashboards) + @dashboard_list_service_v2.delete_items(dashboard_list_id, dashboards) + end + + def get_items_of_dashboard_list(dashboard_list_id) + @dashboard_list_service_v2.get_items(dashboard_list_id) + end + + end + # A simple DogAPI client # # See Dogapi::V1 for the thick underlying clients @@ -13,6 +56,8 @@ module Dogapi # documentation, here[https://github.com/DataDog/dogapi/wiki]. class Client # rubocop:disable Metrics/ClassLength attr_accessor :datadog_host + attr_accessor :v2 + # Support for API version 2. def initialize(api_key, application_key=nil, host=nil, device=nil, silent=true, timeout=nil, endpoint=nil) @@ -50,6 +95,10 @@ def initialize(api_key, application_key=nil, host=nil, device=nil, silent=true, @hosts_svc = Dogapi::V1::HostsService.new(@api_key, @application_key, silent, timeout, @datadog_host) @integration_svc = Dogapi::V1::IntegrationService.new(@api_key, @application_key, silent, timeout, @datadog_host) @usage_svc = Dogapi::V1::UsageService.new(@api_key, @application_key, silent, timeout, @datadog_host) + + # Support for Dashboard List API v2. + @v2 = Dogapi::ClientV2.new(@api_key, @application_key, true, true, @datadog_host) + end # diff --git a/lib/dogapi/v2.rb b/lib/dogapi/v2.rb new file mode 100644 index 00000000..455c0ca8 --- /dev/null +++ b/lib/dogapi/v2.rb @@ -0,0 +1 @@ +require 'dogapi/v2/dashboard_list' diff --git a/lib/dogapi/v2/dashboard_list.rb b/lib/dogapi/v2/dashboard_list.rb new file mode 100644 index 00000000..685df069 --- /dev/null +++ b/lib/dogapi/v2/dashboard_list.rb @@ -0,0 +1,68 @@ +require 'dogapi' + +module Dogapi + class V2 # for namespacing + + # Dashboard List API + class DashboardListService < Dogapi::APIService + + API_VERSION = 'v2' + RESOURCE_NAME = 'dashboard/lists/manual' + SUB_RESOURCE_NAME = 'dashboards' + + def get_items(resource_id) + request( + Net::HTTP::Get, + "/api/#{API_VERSION}/#{RESOURCE_NAME}/#{resource_id}/#{SUB_RESOURCE_NAME}", + nil, + nil, + false + ) + end + + def add_items(resource_id, dashboards) + body = { + dashboards: dashboards + } + + request( + Net::HTTP::Post, + "/api/#{API_VERSION}/#{RESOURCE_NAME}/#{resource_id}/#{SUB_RESOURCE_NAME}", + nil, + body, + true + ) + end + + def update_items(resource_id, dashboards) + body = { + dashboards: dashboards + } + + request( + Net::HTTP::Put, + "/api/#{API_VERSION}/#{RESOURCE_NAME}/#{resource_id}/#{SUB_RESOURCE_NAME}", + nil, + body, + true + ) + end + + def delete_items(resource_id, dashboards) + body = { + dashboards: dashboards + } + + request( + Net::HTTP::Delete, + "/api/#{API_VERSION}/#{RESOURCE_NAME}/#{resource_id}/#{SUB_RESOURCE_NAME}", + nil, + body, + true + ) + end + + end + + end +end diff --git a/spec/integration/dashboard_list_spec.rb b/spec/integration/dashboard_list_spec.rb index 4fc693fe..e3d66839 100644 --- a/spec/integration/dashboard_list_spec.rb +++ b/spec/integration/dashboard_list_spec.rb @@ -6,7 +6,6 @@ DASHBOARD_LIST_ID = 1_234_567 DASHBOARD_LIST_NAME = 'My new dashboard list'.freeze - DASHBOARDS = [ { 'type' => 'custom_timeboard', @@ -83,3 +82,48 @@ :get, "/#{RESOURCE_NAME}/#{DASHBOARD_LIST_ID}/#{SUB_RESOURCE_NAME}" end end + +describe Dogapi::ClientV2 do + RESOURCE_NAME = 'dashboard/lists/manual'.freeze + SUB_RESOURCE_NAME = 'dashboards'.freeze + + DASHBOARD_LIST_ID = 1_234_567 + DASHBOARD_LIST_NAME = 'My new dashboard list'.freeze + DASHBOARDS = [ + { + 'type' => 'custom_timeboard', + 'id' => 1234 + }, + { + 'type' => 'custom_screenboard', + 'id' => 1234 + } + ].freeze + + describe '#add_items_to_dashboard_list' do + it_behaves_like 'an api v2 method', + :add_items_to_dashboard_list, [DASHBOARD_LIST_ID] + [DASHBOARDS], + :post, "/#{RESOURCE_NAME}/#{DASHBOARD_LIST_ID}/#{SUB_RESOURCE_NAME}", + DASHBOARD_LIST_WITH_DASHES_BODY + end + + describe '#update_items_of_dashboard_list' do + it_behaves_like 'an api v2 method', + :update_items_of_dashboard_list, [DASHBOARD_LIST_ID] + [DASHBOARDS], + :put, "/#{RESOURCE_NAME}/#{DASHBOARD_LIST_ID}/#{SUB_RESOURCE_NAME}", + DASHBOARD_LIST_WITH_DASHES_BODY + end + + describe '#delete_items_from_dashboard_list' do + it_behaves_like 'an api v2 method', + :delete_items_from_dashboard_list, [DASHBOARD_LIST_ID] + [DASHBOARDS], + :delete, "/#{RESOURCE_NAME}/#{DASHBOARD_LIST_ID}/#{SUB_RESOURCE_NAME}", + DASHBOARD_LIST_WITH_DASHES_BODY + end + + describe '#get_items_of_dashboard_list' do + it_behaves_like 'an api v2 method', + :get_items_of_dashboard_list, [DASHBOARD_LIST_ID], + :get, "/#{RESOURCE_NAME}/#{DASHBOARD_LIST_ID}/#{SUB_RESOURCE_NAME}" + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index df8040a7..48c41530 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,8 +20,11 @@ module SpecDog let(:api_key) { 'API_KEY' } let(:app_key) { 'APP_KEY' } let(:dog) { Dogapi::Client.new(api_key, app_key, 'data.dog', nil, false) } + let(:dog2) { Dogapi::ClientV2.new(api_key, app_key, 'data.dog', nil, false) } let(:api_url) { "#{DATADOG_HOST}/api/v1" } let(:old_api_url) { "#{DATADOG_HOST}/api" } + let(:api_v2_url) { "#{DATADOG_HOST}/api/v2" } + let(:default_query) { { api_key: api_key, application_key: app_key } } shared_examples 'an api method' do |command, args, request, endpoint, body| @@ -63,7 +66,6 @@ module SpecDog url = api_url + endpoint stub_request(request, /#{url}/).to_return(body: '{}').then.to_raise(StandardError) expect(dog.send(command, *args, *params.values)).to eq ['200', {}] - params.each { |k, v| params[k] = v.join(',') if v.is_a? Array } params = params.merge default_query @@ -88,6 +90,67 @@ module SpecDog ) end end + + # Support for new API version (v2) + + shared_examples 'an api v2 method' do |command, args, request, endpoint, body| + it 'queries the api v2' do + url = api_v2_url + endpoint + stub_request(request, /#{url}/).to_return(body: '{}').then.to_raise(StandardError) + expect(dog2.send(command, *args)).to eq ['200', {}] + body = MultiJson.dump(body) if body + + expect(WebMock).to have_requested(request, url).with( + query: default_query, + body: body + ) + end + end + + shared_examples 'an api v2 method with options' do |command, args, request, endpoint, body| + include_examples 'an api method', command, args, request, endpoint, body + it 'queries the api v2 with options' do + url = api_v2_url + endpoint + options = { 'zzz' => 'aaa' } + stub_request(request, /#{url}/).to_return(body: '{}').then.to_raise(StandardError) + expect(dog2.send(command, *args, options)).to eq ['200', {}] + body = MultiJson.dump(body ? (body.merge options) : options) + + expect(WebMock).to have_requested(request, url).with( + query: default_query, + body: body + ) + end + end + + shared_examples 'an api v2 method with params' do |command, args, request, endpoint, params| + it 'queries the api v2 with params' do + url = api_v2_url + endpoint + stub_request(request, /#{url}/).to_return(body: '{}').then.to_raise(StandardError) + expect(dog2.send(command, *args, *params.values)).to eq ['200', {}] + params.each { |k, v| params[k] = v.join(',') if v.is_a? Array } + params = params.merge default_query + + expect(WebMock).to have_requested(request, url).with( + query: params + ) + end + end + + shared_examples 'an api v2 method with optional params' do |command, args, request, endpoint, opt_params| + include_examples 'an api v2 method', command, args, request, endpoint + it 'queries the api v2 with optional params' do + url = api_v2_url + endpoint + stub_request(request, /#{url}/).to_return(body: '{}').then.to_raise(StandardError) + expect(dog2.send(command, *args, opt_params)).to eq ['200', {}] + opt_params.each { |k, v| opt_params[k] = v.join(',') if v.is_a? Array } + params = opt_params.merge default_query + + expect(WebMock).to have_requested(request, url).with( + query: params + ) + end + end end # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration