Commit ed5add1c authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent de2fb5b8
# 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
......@@ -4,27 +4,41 @@ module PerformanceMonitoring
class PrometheusDashboard
include ActiveModel::Model
attr_accessor :dashboard, :panel_groups
attr_accessor :dashboard, :panel_groups, :path, :environment, :priority
validates :dashboard, presence: true
validates :panel_groups, presence: true
def self.from_json(json_content)
dashboard = new(
dashboard: json_content['dashboard'],
panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) }
)
dashboard.tap(&:validate!)
class << self
def from_json(json_content)
dashboard = new(
dashboard: json_content['dashboard'],
panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) }
)
dashboard.tap(&:validate!)
end
def find_for(project:, user:, path:, options: {})
dashboard_response = Gitlab::Metrics::Dashboard::Finder.find(project, user, options.merge(dashboard_path: path))
return unless dashboard_response[:status] == :success
new(
{
path: path,
environment: options[:environment]
}.merge(dashboard_response[:dashboard])
)
end
end
def to_yaml
self.as_json(only: valid_attributes).to_yaml
self.as_json(only: yaml_valid_attributes).to_yaml
end
private
def valid_attributes
def yaml_valid_attributes
%w(panel_groups panels metrics group priority type title y_label weight id unit label query query_range dashboard)
end
end
......
......@@ -56,7 +56,8 @@ class PrometheusAlert < ApplicationRecord
"for" => "5m",
"labels" => {
"gitlab" => "hook",
"gitlab_alert_id" => prometheus_metric_id
"gitlab_alert_id" => prometheus_metric_id,
"gitlab_prometheus_alert_id" => id
}
}
end
......
---
title: Prevent wrong environment being used when processing Prometheus alert
merge_request: 29119
author:
type: fixed
---
title: Exclude 'trial_ends_on', 'shared_runners_minutes_limit' & 'extra_shared_runners_minutes_limit' from list of exported Group attributes
merge_request: 29259
author:
type: fixed
---
title: Add graphQL interface to fetch metrics dashboard
merge_request: 29112
author:
type: added
......@@ -178,6 +178,18 @@ Plan.default.limits.update!(ci_pipeline_schedules: 100)
## Instance monitoring and metrics
### Incident Management inbound alert limits
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14932) in GitLab 12.5.
Limiting inbound alerts for an incident reduces the number of alerts (issues)
that can be created within a period of time, which can help prevent overloading
your incident responders with duplicate issues. You can reduce the volume of
alerts in the following ways:
- Max requests per period per project, 3600 seconds by default.
- Rate limit period in seconds, 3600 seconds by default.
### Prometheus Alert JSON payloads
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14929) in GitLab 12.6.
......
......@@ -1882,6 +1882,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
"""
......@@ -5278,6 +5288,13 @@ type Metadata {
version: String!
}
type MetricsDashboard {
"""
Path to a file with the dashboard definition
"""
path: String
}
"""
Represents a milestone.
"""
......
......@@ -5580,6 +5580,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",
......@@ -15117,6 +15144,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",
......
......@@ -324,6 +324,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 |
......@@ -815,6 +816,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.
......
......@@ -721,7 +721,7 @@ For example, in order to test new index you can do the following:
Create the index:
```sql
exec CREATE INDEX index_projects_marked_for_deletion ON projects (marked_for_deletion_at) WHERE marked_for_deletion_at IS NOT NULL
exec CREATE INDEX index_projects_last_activity ON projects (last_activity_at) WHERE last_activity_at IS NOT NULL
```
Analyze the table to update its statistics:
......@@ -733,7 +733,7 @@ exec ANALYZE projects
Get the query plan:
```sql
explain SELECT * FROM projects WHERE marked_for_deletion_at < CURRENT_DATE
explain SELECT * FROM projects WHERE last_activity_at < CURRENT_DATE
```
Once done you can rollback your changes:
......
......@@ -309,6 +309,7 @@ The following tables outline the details of expected properties.
| `label` | string | no, but highly encouraged | Defines the legend-label for the query. Should be unique within the panel's metrics. Can contain time series labels as interpolated variables. |
| `query` | string | yes if `query_range` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `query_range` | string | yes if `query` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query_range` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `step` | number | no, value is calculated if not defined | Defines query resolution step width in float number of seconds. Metrics on the same panel should use the same `step` value. |
##### Dynamic labels
......
......@@ -21,6 +21,12 @@ module Gitlab
end
end
def gitlab_prometheus_alert_id
strong_memoize(:gitlab_prometheus_alert_id) do
payload&.dig('labels', 'gitlab_prometheus_alert_id')
end
end
def title
strong_memoize(:title) do
gitlab_alert&.title || parse_title_from_payload
......@@ -120,12 +126,19 @@ module Gitlab
end
def parse_gitlab_alert_from_payload
return unless metric_id
alerts_found = matching_gitlab_alerts
return if alerts_found.blank? || alerts_found.size > 1
alerts_found.first
end
def matching_gitlab_alerts
return unless metric_id || gitlab_prometheus_alert_id
Projects::Prometheus::AlertsFinder
.new(project: project, metric: metric_id)
.new(project: project, metric: metric_id, id: gitlab_prometheus_alert_id)
.execute
.first
end
def parse_title_from_payload
......
......@@ -14,7 +14,7 @@ module Gitlab
define_histogram :gitlab_redis_diff_caching_memory_usage_bytes do
docstring 'Redis diff caching memory usage by key'
buckets [100, 1000, 10000, 100000, 1000000, 10000000]
buckets [100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000]
end
define_counter :gitlab_redis_diff_caching_hit do
......
......@@ -36,6 +36,9 @@ excluded_attributes:
- :runners_token_encrypted
- :saml_discovery_token
- :visibility_level
- :trial_ends_on
- :shared_runners_minute_limit
- :extra_shared_runners_minutes_limit
epics:
- :state_id
......
{"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2020-01-09 12:08:57 UTC","updated_at":"2020-01-09 12:08:57 UTC","description":"A voluptate non sequi temporibus quam at.","avatar":{"url":null},"membership_lock":false,"share_with_group_lock":false,"visibility_level":20,"request_access_enabled":true,"ldap_sync_status":"ready","ldap_sync_error":null,"ldap_sync_last_update_at":null,"ldap_sync_last_successful_update_at":null,"ldap_sync_last_sync_at":null,"lfs_enabled":null,"parent_id":null,"repository_size_limit":null,"require_two_factor_authentication":false,"two_factor_grace_period":48,"plan_id":null,"project_creation_level":2,"file_template_project_id":null,"saml_discovery_token":"JZGRJbe3","custom_project_templates_group_id":null,"auto_devops_enabled":null,"last_ci_minutes_notification_at":null,"last_ci_minutes_usage_notification_level":null,"subgroup_creation_level":1,"emails_disabled":null,"max_pages_size":null,"max_artifacts_size":null,"mentions_disabled":null,"milestones":[],"badges":[],"labels":[{"id":69,"title":"Amfunc","color":"#2658d0","project_id":null,"created_at":"2020-01-09T12:08:57.693Z","updated_at":"2020-01-09T12:08:57.693Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":68,"title":"Aquacell","color":"#f658e0","project_id":null,"created_at":"2020-01-09T12:08:57.688Z","updated_at":"2020-01-09T12:08:57.688Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#333333"},{"id":62,"title":"Bryns","color":"#16f0b9","project_id":null,"created_at":"2020-01-09T12:08:57.672Z","updated_at":"2020-01-09T12:08:57.672Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":61,"title":"Pephfunc","color":"#556319","project_id":null,"created_at":"2020-01-09T12:08:57.669Z","updated_at":"2020-01-09T12:08:57.669Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":67,"title":"Sinesync","color":"#4c44e8","project_id":null,"created_at":"2020-01-09T12:08:57.685Z","updated_at":"2020-01-09T12:08:57.685Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":65,"title":"Traphwood","color":"#71b900","project_id":null,"created_at":"2020-01-09T12:08:57.679Z","updated_at":"2020-01-09T12:08:57.679Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":66,"title":"Tricell","color":"#179ad3","project_id":null,"created_at":"2020-01-09T12:08:57.683Z","updated_at":"2020-01-09T12:08:57.683Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":63,"title":"Trienceforge","color":"#cb1e0e","project_id":null,"created_at":"2020-01-09T12:08:57.674Z","updated_at":"2020-01-09T12:08:57.674Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"},{"id":64,"title":"Trinix","color":"#66ca41","project_id":null,"created_at":"2020-01-09T12:08:57.677Z","updated_at":"2020-01-09T12:08:57.677Z","template":false,"description":null,"group_id":28,"type":"GroupLabel","priorities":[],"textColor":"#FFFFFF"}],"boards":[],"members":[{"id":8,"access_level":10,"source_id":28,"source_type":"Namespace","user_id":13,"notification_level":3,"created_at":"2020-01-09T12:08:57.884Z","updated_at":"2020-01-09T12:08:57.884Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":13,"email":"lorraine@leannon.info","username":"elina.lakin"}},{"id":7,"access_level":30,"source_id":28,"source_type":"Namespace","user_id":1,"notification_level":3,"created_at":"2020-01-09T12:08:57.129Z","updated_at":"2020-01-09T12:08:57.898Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":1,"email":"admin@example.com","username":"root"}},{"id":9,"access_level":20,"source_id":28,"source_type":"Namespace","user_id":8,"notification_level":3,"created_at":"2020-01-09T12:08:57.901Z","updated_at":"2020-01-09T12:08:57.901Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":8,"email":"euna_schroeder@bernier.us","username":"loreen_medhurst"}},{"id":10,"access_level":40,"source_id":28,"source_type":"Namespace","user_id":10,"notification_level":3,"created_at":"2020-01-09T12:08:57.918Z","updated_at":"2020-01-09T12:08:57.918Z","created_by_id":null,"invite_email":null,"invite_token":null,"invite_accepted_at":null,"requested_at":null,"expires_at":null,"ldap":false,"override":false,"user":{"id":10,"email":"glady_green@prohaska.biz","username":"maia_kuhlman"}}],"epics":[{"id":31,"group_id":28,"author_id":13,"assignee_id":null,"iid":1,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.006Z","updated_at":"2020-01-09T12:11:12.006Z","title":"Optio nihil consequatur et vel quaerat cupiditate.","description":"Vel molestias repellendus id voluptatem et non. Blanditiis natus veritatis adipisci qui illo. Sed est veritatis facilis dolore voluptas quibusdam aliquam omnis.\n\nFacere delectus quo architecto explicabo dolores. Quis odit nostrum nobis consequuntur cumque est officiis. Maiores ipsa nobis minus incidunt provident.\n\nVoluptate voluptatem debitis facilis architecto commodi vero. Sit quibusdam consectetur ad quis cupiditate. Exercitationem quasi inventore incidunt itaque optio autem accusantium.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":32,"group_id":28,"author_id":1,"assignee_id":null,"iid":2,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.021Z","updated_at":"2020-01-09T12:11:12.021Z","title":"Maxime cumque totam deleniti excepturi iusto qui sint.","description":"Nesciunt ut sit voluptas iusto rem. Sint doloribus ex et aliquam ea. Nihil necessitatibus distinctio similique incidunt. Consequatur voluptatibus excepturi qui quis quia. Quia optio quod non magnam dolorem id molestiae dignissimos.\n\nAt eligendi fuga veritatis accusamus quo dolores. Eos amet dolores nisi illo voluptatem consequuntur alias. Dolor veniam quas est sed. Ex corporis soluta sit ducimus facere et.\n\nEst odit asperiores vel quae quibusdam maiores quod. Debitis libero quo sed sunt voluptas praesentium. Ut nisi qui et culpa. Consequatur atque aut molestiae sint. Quaerat expedita animi distinctio repellat sed.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":33,"group_id":28,"author_id":8,"assignee_id":null,"iid":3,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.035Z","updated_at":"2020-01-09T12:11:12.035Z","title":"Corrupti perferendis labore omnis pariatur dolores aut repellendus quisquam id.","description":"Eligendi est asperiores minus nulla unde ex. Aspernatur repellat vel deleniti molestiae occaecati odio dicta. Ipsam excepturi quia modi ut autem sed. Omnis quae quam quas ut. Et corrupti aut omnis blanditiis.\n\nDolore dolorem accusamus tempore nihil dolores repellendus sed provident. Commodi consectetur blanditiis et consequatur laborum nulla eveniet facilis. Inventore aut officiis fuga est maiores rerum. Sint aspernatur et necessitatibus omnis qui et blanditiis.\n\nFugiat molestias nulla eos labore rerum perspiciatis non. Minus est et ipsum quis animi et. Id praesentium vitae in eum fugiat incidunt. Voluptas ut nemo ut cum saepe quasi dolores unde.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":34,"group_id":28,"author_id":10,"assignee_id":null,"iid":4,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.049Z","updated_at":"2020-01-09T12:11:12.049Z","title":"Architecto ipsa autem ducimus velit harum doloribus odio fugiat.","description":"Eos perferendis commodi labore id. Ipsa esse non voluptatem sit. Odit et et maiores quis adipisci sed earum.\n\nRerum asperiores consequuntur sed odit. Quis architecto nobis dolor sit consectetur. Inventore praesentium est magnam et reprehenderit impedit occaecati similique.\n\nTemporibus culpa ratione vel facilis perspiciatis rerum. Quisquam ut veniam quia sit totam. Quo ipsam quam dolorum quis. Totam porro nesciunt ut temporibus.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]},{"id":35,"group_id":28,"author_id":10,"assignee_id":null,"iid":5,"updated_by_id":null,"last_edited_by_id":null,"lock_version":0,"start_date":null,"end_date":null,"last_edited_at":null,"created_at":"2020-01-09T12:11:12.062Z","updated_at":"2020-01-09T12:11:12.062Z","title":"Accusantium illo a sint nobis qui explicabo eum iusto facere aut.","description":"Modi laudantium possimus beatae dolorem molestias ut neque. Voluptatem libero harum id cupiditate. Officia et enim quia dolores at adipisci.\n\nEx officia quia at et vel aut. Esse consequatur officiis magnam vel velit eius. Sit cumque quo qui laborum tempore rerum in.\n\nQuibusdam provident quis molestiae laborum odio commodi. Impedit iure voluptatem possimus necessitatibus et error non. Iure est et ipsa recusandae et.","start_date_sourcing_milestone_id":null,"due_date_sourcing_milestone_id":null,"start_date_fixed":null,"due_date_fixed":null,"start_date_is_fixed":null,"due_date_is_fixed":null,"closed_by_id":null,"closed_at":null,"parent_id":null,"relative_position":null,"state_id":"opened","start_date_sourcing_epic_id":null,"due_date_sourcing_epic_id":null,"notes":[]}]}
......@@ -19,18 +19,15 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 7,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"saml_discovery_token": "rBKx3ioz",
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"runners_token": "token",
......@@ -1075,18 +1072,15 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 4351,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"saml_discovery_token": "ki3Xnjw3",
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -1649,18 +1643,15 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 4351,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"saml_discovery_token": "m7cx4AZi",
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......
......@@ -19,18 +19,15 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"saml_discovery_token": "rBKx3ioz",
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......
......@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......
......@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......
......@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
......
# 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
......@@ -9,11 +9,14 @@ describe Gitlab::Alerting::Alert do
let(:payload) { {} }
shared_context 'gitlab alert' do
let(:gitlab_alert_id) { gitlab_alert.prometheus_metric_id.to_s }
let!(:gitlab_alert) { create(:prometheus_alert, project: project) }
let(:gitlab_alert_id) { gitlab_alert.id }
before do
payload['labels'] = { 'gitlab_alert_id' => gitlab_alert_id }
payload['labels'] = {
'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
'gitlab_prometheus_alert_id' => gitlab_alert_id
}
end
end
......@@ -68,6 +71,41 @@ describe Gitlab::Alerting::Alert do
it { is_expected.to be_nil }
end
context 'when two alerts with the same metric exist' do
include_context 'gitlab alert'
let!(:second_gitlab_alert) do
create(:prometheus_alert,
project: project,
prometheus_metric_id: gitlab_alert.prometheus_metric_id
)
end
context 'alert id given in params' do
before do
payload['labels'] = {
'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
'gitlab_prometheus_alert_id' => second_gitlab_alert.id
}
end
it { is_expected.to eq(second_gitlab_alert) }
end
context 'metric id given in params' do
# This tests the case when two alerts are found, as metric id
# is not unique.
# Note the metric id was incorrectly named as 'gitlab_alert_id'
# in PrometheusAlert#to_param.
before do
payload['labels'] = { 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id }
end
it { is_expected.to be_nil }
end
end
end
describe '#title' do
......
......@@ -96,7 +96,8 @@ describe PrometheusAlert do
"for" => "5m",
"labels" => {
"gitlab" => "hook",
"gitlab_alert_id" => metric.id
"gitlab_alert_id" => metric.id,
"gitlab_prometheus_alert_id" => subject.id
})
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