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 ...@@ -15,5 +15,9 @@ module Types
field :state, GraphQL::STRING_TYPE, null: false, field :state, GraphQL::STRING_TYPE, null: false,
description: 'State of the environment, for example: available/stopped' 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
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 ...@@ -4,27 +4,41 @@ module PerformanceMonitoring
class PrometheusDashboard class PrometheusDashboard
include ActiveModel::Model include ActiveModel::Model
attr_accessor :dashboard, :panel_groups attr_accessor :dashboard, :panel_groups, :path, :environment, :priority
validates :dashboard, presence: true validates :dashboard, presence: true
validates :panel_groups, presence: true validates :panel_groups, presence: true
def self.from_json(json_content) class << self
dashboard = new( def from_json(json_content)
dashboard: json_content['dashboard'], dashboard = new(
panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) } dashboard: json_content['dashboard'],
) panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) }
)
dashboard.tap(&:validate!)
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 end
def to_yaml def to_yaml
self.as_json(only: valid_attributes).to_yaml self.as_json(only: yaml_valid_attributes).to_yaml
end end
private 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) %w(panel_groups panels metrics group priority type title y_label weight id unit label query query_range dashboard)
end end
end end
......
...@@ -56,7 +56,8 @@ class PrometheusAlert < ApplicationRecord ...@@ -56,7 +56,8 @@ class PrometheusAlert < ApplicationRecord
"for" => "5m", "for" => "5m",
"labels" => { "labels" => {
"gitlab" => "hook", "gitlab" => "hook",
"gitlab_alert_id" => prometheus_metric_id "gitlab_alert_id" => prometheus_metric_id,
"gitlab_prometheus_alert_id" => id
} }
} }
end 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) ...@@ -178,6 +178,18 @@ Plan.default.limits.update!(ci_pipeline_schedules: 100)
## Instance monitoring and metrics ## 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 ### Prometheus Alert JSON payloads
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14929) in GitLab 12.6. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14929) in GitLab 12.6.
......
...@@ -1882,6 +1882,16 @@ type Environment { ...@@ -1882,6 +1882,16 @@ type Environment {
""" """
id: ID! 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 Human-readable name of the environment
""" """
...@@ -5278,6 +5288,13 @@ type Metadata { ...@@ -5278,6 +5288,13 @@ type Metadata {
version: String! version: String!
} }
type MetricsDashboard {
"""
Path to a file with the dashboard definition
"""
path: String
}
""" """
Represents a milestone. Represents a milestone.
""" """
......
...@@ -5580,6 +5580,33 @@ ...@@ -5580,6 +5580,33 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "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", "name": "name",
"description": "Human-readable name of the environment", "description": "Human-readable name of the environment",
...@@ -15117,6 +15144,33 @@ ...@@ -15117,6 +15144,33 @@
"enumValues": null, "enumValues": null,
"possibleTypes": 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", "kind": "OBJECT",
"name": "Milestone", "name": "Milestone",
......
...@@ -324,6 +324,7 @@ Describes where code is deployed for a project ...@@ -324,6 +324,7 @@ Describes where code is deployed for a project
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `id` | ID! | ID of the environment | | `id` | ID! | ID of the environment |
| `metricsDashboard` | MetricsDashboard | Metrics dashboard schema for the environment |
| `name` | String! | Human-readable name of the environment | | `name` | String! | Human-readable name of the environment |
| `state` | String! | State of the environment, for example: available/stopped | | `state` | String! | State of the environment, for example: available/stopped |
...@@ -815,6 +816,12 @@ Autogenerated return type of MergeRequestSetWip ...@@ -815,6 +816,12 @@ Autogenerated return type of MergeRequestSetWip
| `revision` | String! | Revision | | `revision` | String! | Revision |
| `version` | String! | Version | | `version` | String! | Version |
## MetricsDashboard
| Name | Type | Description |
| --- | ---- | ---------- |
| `path` | String | Path to a file with the dashboard definition |
## Milestone ## Milestone
Represents a milestone. Represents a milestone.
......
...@@ -721,7 +721,7 @@ For example, in order to test new index you can do the following: ...@@ -721,7 +721,7 @@ For example, in order to test new index you can do the following:
Create the index: Create the index:
```sql ```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: Analyze the table to update its statistics:
...@@ -733,7 +733,7 @@ exec ANALYZE projects ...@@ -733,7 +733,7 @@ exec ANALYZE projects
Get the query plan: Get the query plan:
```sql ```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: Once done you can rollback your changes:
......
...@@ -309,6 +309,7 @@ The following tables outline the details of expected properties. ...@@ -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. | | `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` | 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. | | `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 ##### Dynamic labels
......
...@@ -21,6 +21,12 @@ module Gitlab ...@@ -21,6 +21,12 @@ module Gitlab
end end
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 def title
strong_memoize(:title) do strong_memoize(:title) do
gitlab_alert&.title || parse_title_from_payload gitlab_alert&.title || parse_title_from_payload
...@@ -120,12 +126,19 @@ module Gitlab ...@@ -120,12 +126,19 @@ module Gitlab
end end
def parse_gitlab_alert_from_payload 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 Projects::Prometheus::AlertsFinder
.new(project: project, metric: metric_id) .new(project: project, metric: metric_id, id: gitlab_prometheus_alert_id)
.execute .execute
.first
end end
def parse_title_from_payload def parse_title_from_payload
......
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
define_histogram :gitlab_redis_diff_caching_memory_usage_bytes do define_histogram :gitlab_redis_diff_caching_memory_usage_bytes do
docstring 'Redis diff caching memory usage by key' 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 end
define_counter :gitlab_redis_diff_caching_hit do define_counter :gitlab_redis_diff_caching_hit do
......
...@@ -36,6 +36,9 @@ excluded_attributes: ...@@ -36,6 +36,9 @@ excluded_attributes:
- :runners_token_encrypted - :runners_token_encrypted
- :saml_discovery_token - :saml_discovery_token
- :visibility_level - :visibility_level
- :trial_ends_on
- :shared_runners_minute_limit
- :extra_shared_runners_minutes_limit
epics: epics:
- :state_id - :state_id
......
This diff is collapsed.
...@@ -19,18 +19,15 @@ ...@@ -19,18 +19,15 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 7, "parent_id": 7,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"saml_discovery_token": "rBKx3ioz", "saml_discovery_token": "rBKx3ioz",
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"runners_token": "token", "runners_token": "token",
...@@ -1075,18 +1072,15 @@ ...@@ -1075,18 +1072,15 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 4351, "parent_id": 4351,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"saml_discovery_token": "ki3Xnjw3", "saml_discovery_token": "ki3Xnjw3",
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -1649,18 +1643,15 @@ ...@@ -1649,18 +1643,15 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 4351, "parent_id": 4351,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"saml_discovery_token": "m7cx4AZi", "saml_discovery_token": "m7cx4AZi",
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
......
...@@ -19,18 +19,15 @@ ...@@ -19,18 +19,15 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": null, "parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"saml_discovery_token": "rBKx3ioz", "saml_discovery_token": "rBKx3ioz",
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
......
...@@ -20,17 +20,14 @@ ...@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": null, "parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -61,17 +58,14 @@ ...@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -102,17 +96,14 @@ ...@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -143,17 +134,14 @@ ...@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
......
...@@ -20,17 +20,14 @@ ...@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": null, "parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -61,17 +58,14 @@ ...@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -102,17 +96,14 @@ ...@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -143,17 +134,14 @@ ...@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
......
...@@ -20,17 +20,14 @@ ...@@ -20,17 +20,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": null, "parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -61,17 +58,14 @@ ...@@ -61,17 +58,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -102,17 +96,14 @@ ...@@ -102,17 +96,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "subgroup_creation_level": 1,
...@@ -143,17 +134,14 @@ ...@@ -143,17 +134,14 @@
"ldap_sync_last_sync_at": null, "ldap_sync_last_sync_at": null,
"lfs_enabled": null, "lfs_enabled": null,
"parent_id": 283, "parent_id": 283,
"shared_runners_minutes_limit": null,
"repository_size_limit": null, "repository_size_limit": null,
"require_two_factor_authentication": false, "require_two_factor_authentication": false,
"two_factor_grace_period": 48, "two_factor_grace_period": 48,
"plan_id": null, "plan_id": null,
"project_creation_level": 2, "project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null, "file_template_project_id": null,
"custom_project_templates_group_id": null, "custom_project_templates_group_id": null,
"auto_devops_enabled": null, "auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null, "last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null, "last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1, "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 ...@@ -7,7 +7,7 @@ describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do it 'has the expected fields' do
expected_fields = %w[ expected_fields = %w[
name id state name id state metrics_dashboard
] ]
expect(described_class).to have_graphql_fields(*expected_fields) 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 ...@@ -9,11 +9,14 @@ describe Gitlab::Alerting::Alert do
let(:payload) { {} } let(:payload) { {} }
shared_context 'gitlab alert' do 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) { create(:prometheus_alert, project: project) }
let(:gitlab_alert_id) { gitlab_alert.id }
before do 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
end end
...@@ -68,6 +71,41 @@ describe Gitlab::Alerting::Alert do ...@@ -68,6 +71,41 @@ describe Gitlab::Alerting::Alert do
it { is_expected.to be_nil } it { is_expected.to be_nil }
end 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 end
describe '#title' do describe '#title' do
......
...@@ -96,7 +96,8 @@ describe PrometheusAlert do ...@@ -96,7 +96,8 @@ describe PrometheusAlert do
"for" => "5m", "for" => "5m",
"labels" => { "labels" => {
"gitlab" => "hook", "gitlab" => "hook",
"gitlab_alert_id" => metric.id "gitlab_alert_id" => metric.id,
"gitlab_prometheus_alert_id" => subject.id
}) })
end end
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