Commit 447e088a authored by Jose Vargas's avatar Jose Vargas

Add metrics dashboard template finder

This adds the necessary backend that manages
the *.metrics-dashboard.yml template files
parent 1072170f
......@@ -6,7 +6,8 @@ class TemplateFinder
VENDORED_TEMPLATES = HashWithIndifferentAccess.new(
dockerfiles: ::Gitlab::Template::DockerfileTemplate,
gitignores: ::Gitlab::Template::GitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate,
metrics_dashboard_ymls: ::Gitlab::Template::MetricsDashboardTemplate
).freeze
class << self
......
......@@ -200,6 +200,10 @@ module BlobHelper
@gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls, project).execute)
end
def metrics_dashboard_ymls(project)
@metrics_dashboard_ymls ||= template_dropdown_names(TemplateFinder.build(:metrics_dashboard_ymls, project).execute)
end
def dockerfile_names(project)
@dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles, project).execute)
end
......
# Development guide for Metrics Dashboards templates
This document explains how to develop Metrics Dashboards templates
## Place the template file in the relevant directory
All template files reside in the `lib/gitlab/metrics/templates` directory
## Criteria
All the templates must be named with the `*.metrics-dashboard.yml` suffix.
The file must follow the [custom dashboard syntax](../../../operations/metrics/dashboards/yaml.md).
### Make sure the new template can be selected in the UI
All the templates available in `lib/gitlab/metrics/templates` are selectable in the **New File** UI from the repository view as well from the **WebIDE** New File template selector.
![Metrics dashboard template selection](img/metrics_dashboard_template_selection_v13_3.png)
![Metrics dashboard template selection WebIDE](img/metrics_dashboard_template_selection_web_ide_v13_3.png)
......@@ -7,7 +7,8 @@ module EE
CUSTOM_TEMPLATES = HashWithIndifferentAccess.new(
dockerfiles: ::Gitlab::Template::CustomDockerfileTemplate,
gitignores: ::Gitlab::Template::CustomGitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::CustomGitlabCiYmlTemplate
gitlab_ci_ymls: ::Gitlab::Template::CustomGitlabCiYmlTemplate,
metrics_dashboard_ymls: ::Gitlab::Template::MetricsDashboardTemplate
).freeze
attr_reader :custom_templates
......
......@@ -4,7 +4,7 @@ module API
class ProjectTemplates < Grape::API::Instance
include PaginationParams
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses].freeze
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls].freeze
# The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded
# values (e.g. C%2B%2B for C++), so allow % and + as well.
......@@ -14,7 +14,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses) of the template'
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls) of the template'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do
......
# Only one dashboard should be defined per file
# More info: https://docs.gitlab.com/ee/operations/metrics/dashboards/yaml.html
dashboard: 'Single Stat'
# This is where all of the variables that can be manipulated via the UI
# are initialized
# Check out: https://docs.gitlab.com/ee/operations/metrics/dashboards/templating_variables.html#templating-variables-for-metrics-dashboards-core
templating:
variables:
job: 'prometheus'
# For more information about the required properties of panel_groups
# please visit: https://docs.gitlab.com/ee/operations/metrics/dashboards/yaml.html#panel-group-panel_groups-properties
panel_groups:
- group: 'Memory'
panels:
- title: Prometheus
type: single-stat
metrics:
# Queries that make use of variables need to have double curly brackets {}
# set to the variables, per the example below
query: 'max(go_memstats_alloc_bytes{job="{{job}}"}) / 1024 /1024'
unit: '%'
label: "Max"
# Development guide for Metrics Dashboard templates
Please follow [the development guideline](../../../../doc/development/operations/metrics/templates.md)
# frozen_string_literal: true
module Gitlab
module Template
class MetricsDashboardTemplate < BaseTemplate
def content
explanation = "# This file is a template, and might need editing before it works on your project."
[explanation, super].join("\n")
end
class << self
def extension
'.metrics-dashboard.yml'
end
def categories
{
"General" => ''
}
end
def base_dir
Rails.root.join('lib/gitlab/metrics/templates')
end
def finder(project = nil)
Gitlab::Template::Finders::GlobalTemplateFinder.new(self.base_dir, self.extension, self.categories)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Template::MetricsDashboardTemplate do
subject { described_class }
describe '.all' do
it 'strips the metrics-dashboard suffix' do
expect(subject.all.first.name).not_to end_with('metrics-dashboard.yml')
end
it 'combines the globals and rest' do
all = subject.all.map(&:name)
expect(all).to include('Default')
end
it 'ensures that the template name is used exactly once' do
all = subject.all.group_by(&:name)
duplicates = all.select { |_, templates| templates.length > 1 }
expect(duplicates).to be_empty
end
end
describe '.find' do
it 'returns nil if the file does not exist' do
expect(subject.find('nonexistent-file')).to be nil
end
it 'returns the MetricsDashboardYml object of a valid file' do
default_dashboard = subject.find('Default')
expect(default_dashboard).to be_a described_class
expect(default_dashboard.name).to eq('Default')
end
end
describe '.by_category' do
it 'returns sorted results' do
result = described_class.by_category('General')
expect(result).to eq(result.sort)
end
end
describe '#content' do
it 'loads the full file' do
example_dashboard = subject.new(Rails.root.join('lib/gitlab/metrics/templates/Default.metrics-dashboard.yml'))
expect(example_dashboard.name).to eq 'Default'
expect(example_dashboard.content).to start_with('#')
end
end
describe '#<=>' do
it 'sorts lexicographically' do
one = described_class.new('a.metrics-dashboard.yml')
other = described_class.new('z.metrics-dashboard.yml')
expect(one.<=>(other)).to be(-1)
expect([other, one].sort).to eq([one, other])
end
end
end
......@@ -62,6 +62,15 @@ RSpec.describe API::ProjectTemplates do
expect(json_response).to satisfy_one { |template| template['key'] == 'mit' }
end
it 'returns metrics_dashboard_ymls' do
get api("/projects/#{public_project.id}/templates/metrics_dashboard_ymls")
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response).to satisfy_one { |template| template['key'] == 'Default' }
end
it 'returns 400 for an unknown template type' do
get api("/projects/#{public_project.id}/templates/unknown")
......@@ -136,6 +145,14 @@ RSpec.describe API::ProjectTemplates do
expect(json_response['name']).to eq('Android')
end
it 'returns a specific metrics_dashboard_yml' do
get api("/projects/#{public_project.id}/templates/metrics_dashboard_ymls/Default")
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('Default')
end
it 'returns a specific license' do
get api("/projects/#{public_project.id}/templates/licenses/mit")
......@@ -166,6 +183,10 @@ RSpec.describe API::ProjectTemplates do
subject { get api("/projects/#{url_encoded_path}/templates/gitlab_ci_ymls/Android") }
end
it_behaves_like 'accepts project paths with dots' do
subject { get api("/projects/#{url_encoded_path}/templates/metrics_dashboard_ymls/Default") }
end
shared_examples 'path traversal attempt' do |template_type|
it 'rejects invalid filenames' do
get api("/projects/#{public_project.id}/templates/#{template_type}/%2e%2e%2fPython%2ea")
......
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