Commit a74a03d4 authored by Mikolaj Wawrzyniak's avatar Mikolaj Wawrzyniak

Add Metrics Dasboard graphQL resource

In order to allow quering metrics dashboard data for each of
environents we need to add new graphQL entities.
parent 7f4fad0d
# frozen_string_literal: true
module Resolvers
module Metrics
class DashboardResolver < Resolvers::BaseResolver
argument :path, GraphQL::STRING_TYPE,
required: true,
description: "Path to a file which defines metrics dashboard eg: 'config/prometheus/common_metrics.yml'"
type Types::Metrics::DashboardType, null: true
alias_method :environment, :object
def resolve(**args)
return unless environment
::PerformanceMonitoring::PrometheusDashboard.find_for(project: environment.project, user: context[:current_user], path: args[:path], options: { environment: environment })
end
end
end
end
......@@ -15,5 +15,9 @@ module Types
field :state, GraphQL::STRING_TYPE, null: false,
description: 'State of the environment, for example: available/stopped'
field :metrics_dashboard, Types::Metrics::DashboardType, null: true,
description: 'Metrics dashboard schema for the environment',
resolver: Resolvers::Metrics::DashboardResolver
end
end
# frozen_string_literal: true
module Types
module Metrics
# rubocop: disable Graphql/AuthorizeTypes
# Authorization is performed at environment level
class DashboardType < ::Types::BaseObject
graphql_name 'MetricsDashboard'
field :path, GraphQL::STRING_TYPE, null: true,
description: 'Path to a file with the dashboard definition'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
......@@ -1865,6 +1865,16 @@ type Environment {
"""
id: ID!
"""
Metrics dashboard schema for the environment
"""
metricsDashboard(
"""
Path to a file which defines metrics dashboard eg: 'config/prometheus/common_metrics.yml'
"""
path: String!
): MetricsDashboard
"""
Human-readable name of the environment
"""
......@@ -5147,6 +5157,13 @@ type Metadata {
version: String!
}
type MetricsDashboard {
"""
Path to a file with the dashboard definition
"""
path: String
}
"""
Represents a milestone.
"""
......
......@@ -5525,6 +5525,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "metricsDashboard",
"description": "Metrics dashboard schema for the environment",
"args": [
{
"name": "path",
"description": "Path to a file which defines metrics dashboard eg: 'config/prometheus/common_metrics.yml'",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "MetricsDashboard",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "name",
"description": "Human-readable name of the environment",
......@@ -14729,6 +14756,33 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MetricsDashboard",
"description": null,
"fields": [
{
"name": "path",
"description": "Path to a file with the dashboard definition",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Milestone",
......
......@@ -317,6 +317,7 @@ Describes where code is deployed for a project
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | ID of the environment |
| `metricsDashboard` | MetricsDashboard | Metrics dashboard schema for the environment |
| `name` | String! | Human-readable name of the environment |
| `state` | String! | State of the environment, for example: available/stopped |
......@@ -781,6 +782,12 @@ Autogenerated return type of MergeRequestSetWip
| `revision` | String! | Revision |
| `version` | String! | Version |
## MetricsDashboard
| Name | Type | Description |
| --- | ---- | ---------- |
| `path` | String | Path to a file with the dashboard definition |
## Milestone
Represents a milestone.
......
# frozen_string_literal: true
require 'spec_helper'
describe Resolvers::Metrics::DashboardResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
describe '#resolve' do
subject(:resolve_dashboard) { resolve(described_class, obj: parent_object, args: args, ctx: { current_user: current_user }) }
let(:args) do
{
path: 'config/prometheus/common_metrics.yml'
}
end
context 'for environment' do
let(:project) { create(:project) }
let(:parent_object) { create(:environment, project: project) }
before do
project.add_developer(current_user)
end
it 'use ActiveModel class to find matching dashboard', :aggregate_failures do
expected_arguments = { project: project, user: current_user, path: args[:path], options: { environment: parent_object } }
expect(PerformanceMonitoring::PrometheusDashboard).to receive(:find_for).with(expected_arguments).and_return(PerformanceMonitoring::PrometheusDashboard.new)
expect(resolve_dashboard).to be_instance_of PerformanceMonitoring::PrometheusDashboard
end
context 'without parent object' do
let(:parent_object) { nil }
it 'returns nil', :aggregate_failures do
expect(PerformanceMonitoring::PrometheusDashboard).not_to receive(:find_for)
expect(resolve_dashboard).to be_nil
end
end
end
end
end
......@@ -7,7 +7,7 @@ describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do
expected_fields = %w[
name id state
name id state metrics_dashboard
]
expect(described_class).to have_graphql_fields(*expected_fields)
......
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['MetricsDashboard'] do
it { expect(described_class.graphql_name).to eq('MetricsDashboard') }
it 'has the expected fields' do
expected_fields = %w[
path
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Getting Metrics Dashboard' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let(:project) { create(:project) }
let!(:environment) { create(:environment, project: project) }
let(:fields) do
<<~QUERY
#{all_graphql_fields_for('MetricsDashboard'.classify)}
QUERY
end
let(:query) do
%(
query {
project(fullPath:"#{project.full_path}") {
environments(name: "#{environment.name}") {
nodes {
metricsDashboard(path: "#{path}"){
#{fields}
}
}
}
}
}
)
end
context 'for anonymous user' do
before do
post_graphql(query, current_user: current_user)
end
context 'requested dashboard is available' do
let(:path) { 'config/prometheus/common_metrics.yml' }
it_behaves_like 'a working graphql query'
it 'returns nil' do
dashboard = graphql_data.dig('project', 'environments', 'nodes')
expect(dashboard).to be_nil
end
end
end
context 'for user with developer access' do
before do
project.add_developer(current_user)
post_graphql(query, current_user: current_user)
end
context 'requested dashboard is available' do
let(:path) { 'config/prometheus/common_metrics.yml' }
it_behaves_like 'a working graphql query'
it 'returns metrics dashboard' do
dashboard = graphql_data.dig('project', 'environments', 'nodes')[0]['metricsDashboard']
expect(dashboard).to eql("path" => path)
end
end
context 'requested dashboard can not be found' do
let(:path) { 'config/prometheus/i_am_not_here.yml' }
it_behaves_like 'a working graphql query'
it 'return snil' do
dashboard = graphql_data.dig('project', 'environments', 'nodes')[0]['metricsDashboard']
expect(dashboard).to be_nil
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment