diff --git a/.rubocop_todo/gitlab/bounded_contexts.yml b/.rubocop_todo/gitlab/bounded_contexts.yml index 5c7d8b5247d848b87a2735cd40bf826a44e91e8d..db6973711f991fca7b5ac330d473367f49424a96 100644 --- a/.rubocop_todo/gitlab/bounded_contexts.yml +++ b/.rubocop_todo/gitlab/bounded_contexts.yml @@ -995,7 +995,6 @@ Gitlab/BoundedContexts: - 'app/models/generic_commit_status.rb' - 'app/models/gpg_key.rb' - 'app/models/gpg_key_subkey.rb' - - 'app/models/grafana_integration.rb' - 'app/models/group.rb' - 'app/models/group/crm_settings.rb' - 'app/models/group_custom_attribute.rb' @@ -1274,7 +1273,6 @@ Gitlab/BoundedContexts: - 'app/policies/event_policy.rb' - 'app/policies/external_issue_policy.rb' - 'app/policies/global_policy.rb' - - 'app/policies/grafana_integration_policy.rb' - 'app/policies/group_deploy_key_policy.rb' - 'app/policies/group_deploy_keys_group_policy.rb' - 'app/policies/group_group_link_policy.rb' @@ -3853,9 +3851,6 @@ Gitlab/BoundedContexts: - 'lib/gitlab_settings/settings.rb' - 'lib/google_api/auth.rb' - 'lib/google_api/cloud_platform/client.rb' - - 'lib/grafana/client.rb' - - 'lib/grafana/time_window.rb' - - 'lib/grafana/validator.rb' - 'lib/initializer_connections.rb' - 'lib/json_web_token/hmac_token.rb' - 'lib/json_web_token/rsa_token.rb' diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml index 9737aacfae0fbae2d050b457b8b5cbdfb9e6f690..40efd2eee767a1f84a150c53d2381f8672eabfe0 100644 --- a/.rubocop_todo/gitlab/namespaced_class.yml +++ b/.rubocop_todo/gitlab/namespaced_class.yml @@ -162,7 +162,6 @@ Gitlab/NamespacedClass: - 'app/models/generic_commit_status.rb' - 'app/models/gpg_key.rb' - 'app/models/gpg_key_subkey.rb' - - 'app/models/grafana_integration.rb' - 'app/models/group.rb' - 'app/models/group_custom_attribute.rb' - 'app/models/group_deletion_schedule.rb' @@ -357,7 +356,6 @@ Gitlab/NamespacedClass: - 'app/policies/environment_policy.rb' - 'app/policies/external_issue_policy.rb' - 'app/policies/global_policy.rb' - - 'app/policies/grafana_integration_policy.rb' - 'app/policies/group_deploy_key_policy.rb' - 'app/policies/group_deploy_keys_group_policy.rb' - 'app/policies/group_label_policy.rb' diff --git a/.rubocop_todo/gitlab/rails/attr_encrypted.yml b/.rubocop_todo/gitlab/rails/attr_encrypted.yml index f71caaf65d3eef404b39905e7e0c2210d9240487..0e308a739dc97eb67ed45980a222f1bcafdb4824 100644 --- a/.rubocop_todo/gitlab/rails/attr_encrypted.yml +++ b/.rubocop_todo/gitlab/rails/attr_encrypted.yml @@ -22,7 +22,6 @@ Gitlab/Rails/AttrEncrypted: - 'app/models/concerns/packages/debian/distribution_key.rb' - 'app/models/concerns/web_hooks/hook.rb' - 'app/models/error_tracking/project_error_tracking_setting.rb' - - 'app/models/grafana_integration.rb' - 'app/models/incident_management/project_incident_management_setting.rb' - 'app/models/integrations/issue_tracker_data.rb' - 'app/models/integrations/jira_tracker_data.rb' diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml index 6f4b560d379452f2b59249579140f6bdbf7e7053..74c6a058b41a8d6c7b263fe606b578cf8cce1841 100644 --- a/.rubocop_todo/gitlab/strong_memoize_attr.yml +++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml @@ -545,7 +545,6 @@ Gitlab/StrongMemoizeAttr: - 'lib/gitlab/wiki_pages/front_matter_parser.rb' - 'lib/gitlab/x509/signature.rb' - 'lib/gitlab/x509/tag.rb' - - 'lib/grafana/time_window.rb' - 'lib/object_storage/direct_upload.rb' - 'lib/safe_zip/extract_params.rb' - 'lib/sidebars/projects/menus/analytics_menu.rb' diff --git a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml index 1f525038c70fb671550a343eb77e12389220dae3..ed03484e59feae3f58430d2a734046ed8cea47d0 100644 --- a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml +++ b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml @@ -565,7 +565,6 @@ Layout/LineEndStringConcatenationIndentation: - 'spec/services/web_hook_service_spec.rb' - 'spec/services/work_items/related_work_item_links/destroy_service_spec.rb' - 'spec/support/database/prevent_cross_joins.rb' - - 'spec/support/helpers/grafana_api_helpers.rb' - 'spec/support/helpers/graphql/subscriptions/action_cable/mock_action_cable.rb' - 'spec/support/helpers/graphql/subscriptions/action_cable/mock_gitlab_schema.rb' - 'spec/support/helpers/redis_without_keys.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 8d239f460305198cc2f4b6c84b0d1bbe63ee86e7..c02db93f82cc4cd64ddc459ad6fc9b72660fb635 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -3227,7 +3227,6 @@ Layout/LineLength: - 'spec/lib/gitlab/x509/signature_spec.rb' - 'spec/lib/gitlab_spec.rb' - 'spec/lib/google_api/cloud_platform/client_spec.rb' - - 'spec/lib/grafana/validator_spec.rb' - 'spec/lib/kramdown/kramdown_spec.rb' - 'spec/lib/kramdown/parser/atlassian_document_format_spec.rb' - 'spec/lib/mattermost/command_spec.rb' @@ -3316,7 +3315,6 @@ Layout/LineLength: - 'spec/models/error_tracking/error_spec.rb' - 'spec/models/event_spec.rb' - 'spec/models/gpg_key_spec.rb' - - 'spec/models/grafana_integration_spec.rb' - 'spec/models/group_deploy_key_spec.rb' - 'spec/models/group_spec.rb' - 'spec/models/identity_spec.rb' diff --git a/.rubocop_todo/lint/unused_method_argument.yml b/.rubocop_todo/lint/unused_method_argument.yml index 2c4f839b8a5b8093995c7553c76bfe270056e279..16aedbd94c6d1e61214a970a265285cada1feceb 100644 --- a/.rubocop_todo/lint/unused_method_argument.yml +++ b/.rubocop_todo/lint/unused_method_argument.yml @@ -30,7 +30,6 @@ Lint/UnusedMethodArgument: - 'app/graphql/resolvers/merge_request_resolver.rb' - 'app/graphql/resolvers/project_resolver.rb' - 'app/graphql/resolvers/projects/branch_rules_resolver.rb' - - 'app/graphql/resolvers/projects/grafana_integration_resolver.rb' - 'app/graphql/resolvers/release_milestones_resolver.rb' - 'app/graphql/resolvers/users/group_count_resolver.rb' - 'app/graphql/resolvers/users/participants_resolver.rb' diff --git a/.rubocop_todo/rails/time_zone.yml b/.rubocop_todo/rails/time_zone.yml index b7330788d73befa0de707ee50ddc0a48f470d4b3..6c11aca3d43589a336728e459c1ad0d2a7684e9c 100644 --- a/.rubocop_todo/rails/time_zone.yml +++ b/.rubocop_todo/rails/time_zone.yml @@ -30,7 +30,6 @@ Rails/TimeZone: - 'lib/gitlab/loop_helpers.rb' - 'lib/gitlab/prometheus_client.rb' - 'lib/gitlab/task_helpers.rb' - - 'lib/grafana/time_window.rb' - 'lib/json_web_token/token.rb' - 'lib/object_storage/direct_upload.rb' - 'lib/tasks/gitlab/assets.rake' @@ -70,6 +69,5 @@ Rails/TimeZone: - 'spec/lib/gitlab/sidekiq_logging/json_formatter_spec.rb' - 'spec/lib/gitlab/utils/json_size_estimator_spec.rb' - 'spec/lib/gitlab/x509/signature_spec.rb' - - 'spec/lib/grafana/time_window_spec.rb' - 'spec/lib/json_web_token/hmac_token_spec.rb' - 'spec/models/merge_request_diff_commit_spec.rb' diff --git a/.rubocop_todo/rspec/be_eq.yml b/.rubocop_todo/rspec/be_eq.yml index cf64309b4ca7108af0eb67450a8ce9d66b802710..c38611c34a861697be01b3fc0091b5587087407f 100644 --- a/.rubocop_todo/rspec/be_eq.yml +++ b/.rubocop_todo/rspec/be_eq.yml @@ -568,7 +568,6 @@ RSpec/BeEq: - 'spec/graphql/resolvers/feature_flag_resolver_spec.rb' - 'spec/graphql/resolvers/import/source_users_resolver_spec.rb' - 'spec/graphql/resolvers/kas/agent_configurations_resolver_spec.rb' - - 'spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb' - 'spec/graphql/resolvers/repository_branch_names_resolver_spec.rb' - 'spec/graphql/resolvers/snippets/blobs_resolver_spec.rb' - 'spec/graphql/subscriptions/issuable_updated_spec.rb' diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml index 77ebb45adff21bcb34468389ccac6525d9311d91..def479bfd027877c94a4f644e9ee25c174cd12c3 100644 --- a/.rubocop_todo/rspec/context_wording.yml +++ b/.rubocop_todo/rspec/context_wording.yml @@ -1909,7 +1909,6 @@ RSpec/ContextWording: - 'spec/models/error_tracking/error_spec.rb' - 'spec/models/event_spec.rb' - 'spec/models/gpg_key_spec.rb' - - 'spec/models/grafana_integration_spec.rb' - 'spec/models/group_label_spec.rb' - 'spec/models/group_spec.rb' - 'spec/models/hooks/system_hook_spec.rb' diff --git a/.rubocop_todo/rspec/example_without_description.yml b/.rubocop_todo/rspec/example_without_description.yml index 8a0824e4f97df65d0721246580e6ab79d19ab0c7..f8afc318d88dea956646f9a7c996b76a2689995d 100644 --- a/.rubocop_todo/rspec/example_without_description.yml +++ b/.rubocop_todo/rspec/example_without_description.yml @@ -360,7 +360,6 @@ RSpec/ExampleWithoutDescription: - 'spec/lib/gitlab/user_access_spec.rb' - 'spec/lib/gitlab/utils/lazy_attributes_spec.rb' - 'spec/lib/gitlab/wiki_pages/front_matter_parser_spec.rb' - - 'spec/lib/grafana/client_spec.rb' - 'spec/lib/json_web_token/rsa_token_spec.rb' - 'spec/lib/release_highlights/validator/entry_spec.rb' - 'spec/lib/sbom/package_url/decoder_spec.rb' diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml index 2fc43bbda9af76793cd666d30056109c4323161d..1842cea83a5c7f3a3b4572822c69c407af45edfd 100644 --- a/.rubocop_todo/rspec/feature_category.yml +++ b/.rubocop_todo/rspec/feature_category.yml @@ -1391,7 +1391,6 @@ RSpec/FeatureCategory: - 'spec/graphql/resolvers/project_packages_resolver_spec.rb' - 'spec/graphql/resolvers/project_resolver_spec.rb' - 'spec/graphql/resolvers/projects/fork_targets_resolver_spec.rb' - - 'spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb' - 'spec/graphql/resolvers/projects/services_resolver_spec.rb' - 'spec/graphql/resolvers/projects/snippets_resolver_spec.rb' - 'spec/graphql/resolvers/recent_boards_resolver_spec.rb' @@ -2918,9 +2917,6 @@ RSpec/FeatureCategory: - 'spec/lib/gitlab_edition_spec.rb' - 'spec/lib/google_api/auth_spec.rb' - 'spec/lib/google_api/cloud_platform/client_spec.rb' - - 'spec/lib/grafana/client_spec.rb' - - 'spec/lib/grafana/time_window_spec.rb' - - 'spec/lib/grafana/validator_spec.rb' - 'spec/lib/initializer_connections_spec.rb' - 'spec/lib/json_web_token/hmac_token_spec.rb' - 'spec/lib/json_web_token/token_spec.rb' @@ -3138,7 +3134,6 @@ RSpec/FeatureCategory: - 'spec/models/generic_commit_status_spec.rb' - 'spec/models/gpg_key_spec.rb' - 'spec/models/gpg_key_subkey_spec.rb' - - 'spec/models/grafana_integration_spec.rb' - 'spec/models/group_custom_attribute_spec.rb' - 'spec/models/group_deploy_key_spec.rb' - 'spec/models/group_deploy_keys_group_spec.rb' diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml index 5e9f186cc6173cd320719c6f9a347eec75996d9d..940e16518791e2c457f2c859e228e43c7695e3c6 100644 --- a/.rubocop_todo/rspec/named_subject.yml +++ b/.rubocop_todo/rspec/named_subject.yml @@ -2155,8 +2155,6 @@ RSpec/NamedSubject: - 'spec/lib/gitlab_spec.rb' - 'spec/lib/google_api/auth_spec.rb' - 'spec/lib/google_api/cloud_platform/client_spec.rb' - - 'spec/lib/grafana/time_window_spec.rb' - - 'spec/lib/grafana/validator_spec.rb' - 'spec/lib/json_web_token/rsa_token_spec.rb' - 'spec/lib/kramdown/kramdown_spec.rb' - 'spec/lib/mattermost/client_spec.rb' diff --git a/.rubocop_todo/style/guard_clause.yml b/.rubocop_todo/style/guard_clause.yml index 903193da4906b7fc3a003bb95eb8632b2d2061b2..c32c03e01f071b372e73340944897b201aac6a69 100644 --- a/.rubocop_todo/style/guard_clause.yml +++ b/.rubocop_todo/style/guard_clause.yml @@ -73,7 +73,6 @@ Style/GuardClause: - 'app/models/environment.rb' - 'app/models/error_tracking/project_error_tracking_setting.rb' - 'app/models/generic_commit_status.rb' - - 'app/models/grafana_integration.rb' - 'app/models/integrations/datadog.rb' - 'app/models/internal_id.rb' - 'app/models/issue.rb' diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml index 6690357a514584f4274b3e7fc49518e305faa360..665977dfa43313ffb3a3fb112a22bc740b9f3934 100644 --- a/.rubocop_todo/style/if_unless_modifier.yml +++ b/.rubocop_todo/style/if_unless_modifier.yml @@ -29,7 +29,6 @@ Style/IfUnlessModifier: - 'app/models/environment.rb' - 'app/models/error_tracking/project_error_tracking_setting.rb' - 'app/models/generic_commit_status.rb' - - 'app/models/grafana_integration.rb' - 'app/models/integrations/datadog.rb' - 'app/models/issue.rb' - 'app/models/issue_email_participant.rb' diff --git a/.rubocop_todo/style/string_concatenation.yml b/.rubocop_todo/style/string_concatenation.yml index 10dc434cb643fd1408c9213521c90458a289d058..547fae8bb7cd9b6da61af293deaef70963183f49 100644 --- a/.rubocop_todo/style/string_concatenation.yml +++ b/.rubocop_todo/style/string_concatenation.yml @@ -175,7 +175,6 @@ Style/StringConcatenation: - 'spec/models/concerns/pg_full_text_searchable_spec.rb' - 'spec/models/container_repository_spec.rb' - 'spec/models/custom_emoji_spec.rb' - - 'spec/models/grafana_integration_spec.rb' - 'spec/models/integrations/campfire_spec.rb' - 'spec/models/integrations/chat_message/pipeline_message_spec.rb' - 'spec/models/integrations/chat_message/push_message_spec.rb' diff --git a/app/graphql/resolvers/projects/grafana_integration_resolver.rb b/app/graphql/resolvers/projects/grafana_integration_resolver.rb deleted file mode 100644 index 030139734ed18d2eab57b2aa37f808d648484816..0000000000000000000000000000000000000000 --- a/app/graphql/resolvers/projects/grafana_integration_resolver.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module Resolvers - module Projects - class GrafanaIntegrationResolver < BaseResolver - type Types::GrafanaIntegrationType, null: true - - alias_method :project, :object - - def resolve(**args) - return unless project.is_a? Project - - project.grafana_integration - end - end - end -end diff --git a/app/graphql/types/grafana_integration_type.rb b/app/graphql/types/grafana_integration_type.rb index 8426506d95423f92d05f0f329c483002fb1b991b..eb77f22486bb23efe365c5fef64717757cf2241c 100644 --- a/app/graphql/types/grafana_integration_type.rb +++ b/app/graphql/types/grafana_integration_type.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# Deprecated: +# Remove alongside query during any major release. module Types class GrafanaIntegrationType < ::Types::BaseObject graphql_name 'GrafanaIntegration' diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index a46dd747f58de5b7f71ffe8f32e5709de6684c8a..c2cbcd1bca6cb1e5205561488d3c807126fdfbd9 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -478,7 +478,10 @@ def self.authorization_scopes field :grafana_integration, Types::GrafanaIntegrationType, null: true, description: 'Grafana integration details for the project.', - resolver: Resolvers::Projects::GrafanaIntegrationResolver + deprecated: { + reason: 'Feature was removed in 16.0. Always returns null', + milestone: '18.3' + } field :snippets, Types::SnippetType.connection_type, null: true, @@ -1075,6 +1078,8 @@ def permanent_deletion_date permanent_deletion_date_formatted(project) || permanent_deletion_date_formatted end + def grafana_integration; end + private def project diff --git a/app/models/grafana_integration.rb b/app/models/grafana_integration.rb deleted file mode 100644 index be157065a44d3f488d7785c45461faf26f299ceb..0000000000000000000000000000000000000000 --- a/app/models/grafana_integration.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -class GrafanaIntegration < ApplicationRecord - include Gitlab::EncryptedAttribute - - belongs_to :project - - attr_encrypted :token, - mode: :per_attribute_iv, - algorithm: 'aes-256-gcm', - key: :db_key_base_32 - - before_validation :check_token_changes - - validates :grafana_url, - length: { maximum: 1024 }, - addressable_url: { enforce_sanitization: true, ascii_only: true } - - validates :encrypted_token, :project, presence: true - - validates :enabled, inclusion: { in: [true, false] } - - before_validation :reset_token - - scope :enabled, -> { where(enabled: true) } - - def client - return unless enabled? - - @client ||= ::Grafana::Client.new(api_url: grafana_url.chomp('/'), token: token) - end - - def masked_token - mask(encrypted_token) - end - - def masked_token_was - mask(encrypted_token_was) - end - - private - - def reset_token - if grafana_url_changed? && !encrypted_token_changed? - self.token = nil - end - end - - def token - attr_encrypted_decrypt(:token, encrypted_token) - end - - def check_token_changes - return unless [encrypted_token_was, masked_token_was].include?(token) - - clear_attribute_changes [:token, :encrypted_token, :encrypted_token_iv] - end - - def mask(token) - token&.squish&.gsub(/./, '*') - end -end diff --git a/app/models/project.rb b/app/models/project.rb index 096446555d0583e2eec5f907eb8b0855af105b19..c4999976abf0e55e44b001ca924421ba5468cf5a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -312,7 +312,6 @@ def self.integration_association_name(name) has_one :project_repository, inverse_of: :project has_one :incident_management_setting, inverse_of: :project, class_name: 'IncidentManagement::ProjectIncidentManagementSetting' has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting' - has_one :grafana_integration, inverse_of: :project has_one :project_setting, inverse_of: :project, autosave: true has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting' has_one :service_desk_setting, class_name: 'ServiceDeskSetting' @@ -534,7 +533,6 @@ def with_developer_access accepts_nested_attributes_for :incident_management_setting, update_only: true accepts_nested_attributes_for :error_tracking_setting, update_only: true - accepts_nested_attributes_for :grafana_integration, update_only: true, allow_destroy: true accepts_nested_attributes_for :prometheus_integration, update_only: true accepts_nested_attributes_for :alerting_setting, update_only: true diff --git a/app/policies/grafana_integration_policy.rb b/app/policies/grafana_integration_policy.rb deleted file mode 100644 index 529a1fe04936bcc0b4e34c23aebb98ed7f6b3fc5..0000000000000000000000000000000000000000 --- a/app/policies/grafana_integration_policy.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -class GrafanaIntegrationPolicy < BasePolicy - delegate { @subject.project } -end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index f6f244c62aa2903dccb8c1230c41031748c64621..618e6bed0dba73dbfe62026034c8d56c4ac8c5f7 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -436,8 +436,6 @@ class ProjectPolicy < BasePolicy rule { guest & can?(:download_code) }.enable :build_download_code rule { guest & can?(:read_container_image) }.enable :build_read_container_image - rule { guest & ~public_project }.enable :read_grafana - rule { can?(:reporter_access) }.policy do enable :admin_issue_board enable :read_code @@ -471,7 +469,6 @@ class ProjectPolicy < BasePolicy enable :read_ci_cd_analytics enable :read_external_emails enable :read_internal_note - enable :read_grafana enable :export_work_items enable :create_design enable :update_design diff --git a/db/docs/grafana_integrations.yml b/db/docs/deleted_tables/grafana_integrations.yml similarity index 74% rename from db/docs/grafana_integrations.yml rename to db/docs/deleted_tables/grafana_integrations.yml index b3bc8f35da26d9bc2bbfd4978760369fe4f112dc..6a1e31aa6cc40effe7ae3ff63def273f00346e0c 100644 --- a/db/docs/grafana_integrations.yml +++ b/db/docs/deleted_tables/grafana_integrations.yml @@ -11,3 +11,5 @@ gitlab_schema: gitlab_main_cell sharding_key: project_id: projects table_size: small +removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/199243 +removed_in_milestone: '18.3' diff --git a/db/post_migrate/20250725071156_remove_grafana_integrations_fk_project_id.rb b/db/post_migrate/20250725071156_remove_grafana_integrations_fk_project_id.rb new file mode 100644 index 0000000000000000000000000000000000000000..0046419c8ecca175f33518af548bc2dc61d37053 --- /dev/null +++ b/db/post_migrate/20250725071156_remove_grafana_integrations_fk_project_id.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class RemoveGrafanaIntegrationsFkProjectId < Gitlab::Database::Migration[2.3] + milestone '18.3' + disable_ddl_transaction! + + CONSTRAINT_NAME = 'fk_rails_18d0e2b564' + + def up + with_lock_retries do + remove_foreign_key_if_exists( + :grafana_integrations, + column: :project_id, + on_delete: :cascade, + name: CONSTRAINT_NAME + ) + end + end + + def down + add_concurrent_foreign_key( + :grafana_integrations, + :projects, + column: :project_id, + on_delete: :cascade, + name: CONSTRAINT_NAME + ) + end +end diff --git a/db/post_migrate/20250725071302_remove_grafana_integrations.rb b/db/post_migrate/20250725071302_remove_grafana_integrations.rb new file mode 100644 index 0000000000000000000000000000000000000000..5f3800d5256f9c94560f90ced504c87212a7de1e --- /dev/null +++ b/db/post_migrate/20250725071302_remove_grafana_integrations.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class RemoveGrafanaIntegrations < Gitlab::Database::Migration[2.3] + milestone '18.3' + + def up + drop_table :grafana_integrations + end + + def down + execute <<~SQL + CREATE TABLE grafana_integrations ( + id bigint NOT NULL, + project_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + encrypted_token character varying(255) NOT NULL, + encrypted_token_iv character varying(255) NOT NULL, + grafana_url character varying(1024) NOT NULL, + enabled boolean DEFAULT false NOT NULL + ); + + CREATE SEQUENCE grafana_integrations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + ALTER SEQUENCE grafana_integrations_id_seq OWNED BY grafana_integrations.id; + + ALTER TABLE ONLY grafana_integrations ALTER COLUMN id SET DEFAULT nextval('grafana_integrations_id_seq'::regclass); + + ALTER TABLE ONLY grafana_integrations ADD CONSTRAINT grafana_integrations_pkey PRIMARY KEY (id); + + CREATE INDEX index_grafana_integrations_on_enabled ON grafana_integrations USING btree (enabled) WHERE (enabled IS TRUE); + + CREATE INDEX index_grafana_integrations_on_project_id ON grafana_integrations USING btree (project_id); + SQL + end +end diff --git a/db/schema_migrations/20250725071156 b/db/schema_migrations/20250725071156 new file mode 100644 index 0000000000000000000000000000000000000000..d31eb24786e0c063b65fca448e4dc6d5076e63bd --- /dev/null +++ b/db/schema_migrations/20250725071156 @@ -0,0 +1 @@ +96431864166b88fa736d6730fc3429c696084b32f64db695ed22474f02466ba0 \ No newline at end of file diff --git a/db/schema_migrations/20250725071302 b/db/schema_migrations/20250725071302 new file mode 100644 index 0000000000000000000000000000000000000000..dbf08c4f8a43815a538da45c56a72071b6e27f95 --- /dev/null +++ b/db/schema_migrations/20250725071302 @@ -0,0 +1 @@ +aa36dc97300cb6cbc57d12367f40fa22046920a248829b007ff6583936cd62ff \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index a87a45b39b8286acf840800b8ebdbe0092fa7dbd..efe9ce9036523961e27ea96c1253de1e1f55c227 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -15369,26 +15369,6 @@ CREATE SEQUENCE gpg_signatures_id_seq ALTER SEQUENCE gpg_signatures_id_seq OWNED BY gpg_signatures.id; -CREATE TABLE grafana_integrations ( - id bigint NOT NULL, - project_id bigint NOT NULL, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL, - encrypted_token character varying(255) NOT NULL, - encrypted_token_iv character varying(255) NOT NULL, - grafana_url character varying(1024) NOT NULL, - enabled boolean DEFAULT false NOT NULL -); - -CREATE SEQUENCE grafana_integrations_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER SEQUENCE grafana_integrations_id_seq OWNED BY grafana_integrations.id; - CREATE TABLE group_crm_settings ( group_id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -28130,8 +28110,6 @@ ALTER TABLE ONLY gpg_keys ALTER COLUMN id SET DEFAULT nextval('gpg_keys_id_seq': ALTER TABLE ONLY gpg_signatures ALTER COLUMN id SET DEFAULT nextval('gpg_signatures_id_seq'::regclass); -ALTER TABLE ONLY grafana_integrations ALTER COLUMN id SET DEFAULT nextval('grafana_integrations_id_seq'::regclass); - ALTER TABLE ONLY group_crm_settings ALTER COLUMN group_id SET DEFAULT nextval('group_crm_settings_group_id_seq'::regclass); ALTER TABLE ONLY group_custom_attributes ALTER COLUMN id SET DEFAULT nextval('group_custom_attributes_id_seq'::regclass); @@ -30650,9 +30628,6 @@ ALTER TABLE ONLY gpg_keys ALTER TABLE ONLY gpg_signatures ADD CONSTRAINT gpg_signatures_pkey PRIMARY KEY (id); -ALTER TABLE ONLY grafana_integrations - ADD CONSTRAINT grafana_integrations_pkey PRIMARY KEY (id); - ALTER TABLE ONLY group_audit_events ADD CONSTRAINT group_audit_events_pkey PRIMARY KEY (id, created_at); @@ -36101,10 +36076,6 @@ CREATE INDEX index_gpg_signatures_on_gpg_key_subkey_id ON gpg_signatures USING b CREATE INDEX index_gpg_signatures_on_project_id ON gpg_signatures USING btree (project_id); -CREATE INDEX index_grafana_integrations_on_enabled ON grafana_integrations USING btree (enabled) WHERE (enabled IS TRUE); - -CREATE INDEX index_grafana_integrations_on_project_id ON grafana_integrations USING btree (project_id); - CREATE INDEX index_group_crm_settings_on_group_id ON group_crm_settings USING btree (group_id); CREATE INDEX index_group_crm_settings_on_source_group_id ON group_crm_settings USING btree (source_group_id); @@ -45282,9 +45253,6 @@ ALTER TABLE ONLY audit_events_streaming_http_group_namespace_filters ALTER TABLE ONLY cluster_providers_aws ADD CONSTRAINT fk_rails_18983d9ea4 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE; -ALTER TABLE ONLY grafana_integrations - ADD CONSTRAINT fk_rails_18d0e2b564 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; - ALTER TABLE ONLY queries_service_pings ADD CONSTRAINT fk_rails_18dedc7d8e FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index b95df0efde29da0ea532e3bb23a2eea85924b3e0..d0502161d9490f120bd182603f079aa0d9547903 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -37292,7 +37292,7 @@ Project-level settings for product analytics provider. | `forksCount` | [`Int!`](#int) | Number of times the project has been forked. | | `fullPath` | [`ID!`](#id) | Full path of the project. | | `googleCloudArtifactRegistryRepository` {{< icon name="warning-solid" >}} | [`GoogleCloudArtifactRegistryRepository`](#googlecloudartifactregistryrepository) | **Introduced** in GitLab 16.10. **Status**: Experiment. Google Artifact Registry repository. Returns `null` if the GitLab instance is not a SaaS instance. | -| `grafanaIntegration` | [`GrafanaIntegration`](#grafanaintegration) | Grafana integration details for the project. | +| `grafanaIntegration` {{< icon name="warning-solid" >}} | [`GrafanaIntegration`](#grafanaintegration) | **Deprecated** in GitLab 18.3. Feature was removed in 16.0. Always returns null. | | `group` | [`Group`](#group) | Group of the project. | | `hasJiraVulnerabilityIssueCreationEnabled` | [`Boolean!`](#boolean) | Indicates whether Jira issue creation from vulnerabilities is enabled. | | `httpUrlToRepo` | [`String`](#string) | URL to connect to the project via HTTPS. | diff --git a/lib/grafana/client.rb b/lib/grafana/client.rb deleted file mode 100644 index 44808f8bb5a54e22e0199f42de4ba28b11305a33..0000000000000000000000000000000000000000 --- a/lib/grafana/client.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -module Grafana - class Client - Error = Class.new(StandardError) - - # @param api_url [String] Base URL of the Grafana instance - # @param token [String] Admin-level API token for instance - def initialize(api_url:, token:) - @api_url = api_url - @token = token - end - - # @param uid [String] Unique identifier for a Grafana dashboard - def get_dashboard(uid:) - http_get("#{@api_url}/api/dashboards/uid/#{uid}") - end - - # @param name [String] Unique identifier for a Grafana datasource - def get_datasource(name:) - # CGI#escape formats strings such that the Grafana endpoint - # will not recognize the dashboard name. Prefer Addressable::URI#encode_component. - http_get("#{@api_url}/api/datasources/name/#{Addressable::URI.encode_component(name)}") - end - - # @param datasource_id [String] Grafana ID for the datasource - # @param proxy_path [String] Path to proxy - ex) 'api/v1/query_range' - def proxy_datasource(datasource_id:, proxy_path:, query: {}) - http_get("#{@api_url}/api/datasources/proxy/#{datasource_id}/#{proxy_path}", query: query) - end - - private - - def http_get(url, params = {}) - response = handle_request_exceptions do - Gitlab::HTTP.get(url, **request_params.merge(params)) - end - - handle_response(response) - end - - def request_params - { - headers: { - 'Authorization' => "Bearer #{@token}", - 'Accept' => 'application/json', - 'Content-Type' => 'application/json' - }, - follow_redirects: false - } - end - - def handle_request_exceptions - yield - rescue Gitlab::HTTP::Error - raise_error 'Error when connecting to Grafana' - rescue Net::OpenTimeout - raise_error 'Connection to Grafana timed out' - rescue SocketError - raise_error 'Received SocketError when trying to connect to Grafana' - rescue OpenSSL::SSL::SSLError - raise_error 'Grafana returned invalid SSL data' - rescue Errno::ECONNREFUSED - raise_error 'Connection refused' - rescue StandardError => e - raise_error "Grafana request failed due to #{e.class}" - end - - def handle_response(response) - return response if response.code == 200 - - raise_error "Grafana response status code: #{response.code}, Message: #{response.body}" - end - - def raise_error(message) - raise Client::Error, message - end - end -end diff --git a/lib/grafana/time_window.rb b/lib/grafana/time_window.rb deleted file mode 100644 index 6cc757d77c553a92d20b46861000d32ae730b8d9..0000000000000000000000000000000000000000 --- a/lib/grafana/time_window.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -module Grafana - # Allows for easy formatting and manipulations of timestamps - # coming from a Grafana url - class TimeWindow - include ::Gitlab::Utils::StrongMemoize - - def initialize(from, to) - @from = from - @to = to - end - - def formatted - { - start: window[:from].formatted, - end: window[:to].formatted - } - end - - def in_milliseconds - window.transform_values(&:to_ms) - end - - private - - def window - strong_memoize(:window) do - specified_window - rescue Timestamp::Error - default_window - end - end - - def specified_window - RangeWithDefaults.new( - from: Timestamp.from_ms_since_epoch(@from), - to: Timestamp.from_ms_since_epoch(@to) - ).to_hash - end - - def default_window - RangeWithDefaults.new.to_hash - end - end - - # For incomplete time ranges, adds default parameters to - # achieve a complete range. If both full range is provided, - # range will be returned. - class RangeWithDefaults - DEFAULT_RANGE = 8.hours - - # @param from [Grafana::Timestamp, nil] Start of the expected range - # @param to [Grafana::Timestamp, nil] End of the expected range - def initialize(from: nil, to: nil) - @from = from - @to = to - - apply_defaults! - end - - def to_hash - { from: @from, to: @to }.compact - end - - private - - def apply_defaults! - @to ||= @from ? relative_end : Timestamp.new(Time.now) - @from ||= relative_start - end - - def relative_start - Timestamp.new(DEFAULT_RANGE.before(@to.time)) - end - - def relative_end - Timestamp.new(DEFAULT_RANGE.since(@from.time)) - end - end - - # Offers a consistent API for timestamps originating from - # Grafana or other sources, allowing for formatting of timestamps - # as consumed by Grafana-related utilities - class Timestamp - Error = Class.new(StandardError) - - attr_accessor :time - - # @param timestamp [Time] - def initialize(time) - @time = time - end - - # Formats a timestamp from Grafana for compatibility with - # parsing in JS via `new Date(timestamp)` - def formatted - time.utc.strftime('%FT%TZ') - end - - # Converts to milliseconds since epoch - def to_ms - time.to_i * 1000 - end - - class << self - # @param time [String] Representing milliseconds since epoch. - # This is what JS "decided" unix is. - def from_ms_since_epoch(time) - return if time.nil? - - raise Error, 'Expected milliseconds since epoch' unless ms_since_epoch?(time) - - new(cast_ms_to_time(time)) - end - - private - - def cast_ms_to_time(time) - Time.at(time.to_i / 1000.0) - end - - def ms_since_epoch?(time) - ms = time.to_i - - ms.to_s == time && ms.bit_length < 64 - end - end - end -end diff --git a/lib/grafana/validator.rb b/lib/grafana/validator.rb deleted file mode 100644 index a6386a3939489177eeb98001846123d359c8553d..0000000000000000000000000000000000000000 --- a/lib/grafana/validator.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -# Performs checks on whether resources from Grafana can be handled -# We have certain restrictions on which formats we accept. -# Some are technical requirements, others are simplifications. -module Grafana - class Validator - Error = Class.new(StandardError) - - attr_reader :grafana_dashboard, :datasource, :panel, :query_params - - UNSUPPORTED_GRAFANA_GLOBAL_VARS = %w[ - $__interval_ms - $__timeFilter - $__name - $timeFilter - $interval - ].freeze - - def initialize(grafana_dashboard, datasource, panel, query_params) - @grafana_dashboard = grafana_dashboard - @datasource = datasource - @panel = panel - @query_params = query_params - end - - def validate! - validate_query_params! - validate_panel_type! - validate_variable_definitions! - validate_global_variables! - validate_datasource! if datasource - end - - def valid? - validate! - - true - rescue ::Grafana::Validator::Error - false - end - - private - - def validate_query_params! - return if [:from, :to].all? { |param| query_params.include?(param) } - - raise_error 'Grafana query parameters must include from and to.' - end - - # We may choose to support other panel types in future. - def validate_panel_type! - return if panel && panel[:type] == 'graph' && panel[:lines] - - raise_error 'Panel type must be a line graph.' - end - - # We must require variable definitions to create valid prometheus queries. - def validate_variable_definitions! - return unless grafana_dashboard[:dashboard][:templating] - - return if grafana_dashboard[:dashboard][:templating][:list].all? do |variable| - query_params[:"var-#{variable[:name]}"].present? - end - - raise_error 'All Grafana variables must be defined in the query parameters.' - end - - # We may choose to support further Grafana variables in future. - def validate_global_variables! - return unless panel_contains_unsupported_vars? - - raise_error "Prometheus must not include #{UNSUPPORTED_GRAFANA_GLOBAL_VARS}" - end - - # We may choose to support additional datasources in future. - def validate_datasource! - return if datasource[:access] == 'proxy' && datasource[:type] == 'prometheus' - - raise_error 'Only Prometheus datasources with proxy access in Grafana are supported.' - end - - def panel_contains_unsupported_vars? - panel[:targets].any? do |target| - UNSUPPORTED_GRAFANA_GLOBAL_VARS.any? do |variable| - target[:expr].include?(variable) - end - end - end - - def raise_error(message) - raise Validator::Error, message - end - end -end diff --git a/spec/benchmarks/banzai_benchmark.rb b/spec/benchmarks/banzai_benchmark.rb index f46c9ac7e8f3e34a9ae97c8e46f1c43a3c8a7d99..095ee308568db794ace084a0b360409022d437d3 100644 --- a/spec/benchmarks/banzai_benchmark.rb +++ b/spec/benchmarks/banzai_benchmark.rb @@ -34,7 +34,6 @@ let_it_be(:wiki_page) { feature.wiki_page } let_it_be(:markdown_text) { feature.raw_markdown } let_it_be(:glfm_engine) { Banzai::Filter::MarkdownFilter::GLFM_ENGINE } - let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } let_it_be(:default_context) do { project: project, diff --git a/spec/factories/grafana_integrations.rb b/spec/factories/grafana_integrations.rb deleted file mode 100644 index a647ef8d2ecc83d4b13c0ee993497e5a6bef00f0..0000000000000000000000000000000000000000 --- a/spec/factories/grafana_integrations.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :grafana_integration, class: 'GrafanaIntegration' do - project - grafana_url { 'https://grafana.example.com' } - token { SecureRandom.hex(10) } - enabled { true } - end -end diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb index f99217b0b557b5a8c552a020de3ed6b282282049..a8ec96c6bb121effafb9176607bdcd289354b5bc 100644 --- a/spec/factories/usage_data.rb +++ b/spec/factories/usage_data.rb @@ -77,10 +77,6 @@ # Cluster Integrations create(:clusters_integrations_prometheus, cluster: gcp_cluster) - create(:grafana_integration, project: projects[0], enabled: true) - create(:grafana_integration, project: projects[1], enabled: true) - create(:grafana_integration, project: projects[2], enabled: false) - create(:generic_package, project: projects[0], created_at: 3.days.ago) create(:generic_package, project: projects[0], created_at: 3.days.ago) create(:generic_package, project: projects[1], created_at: 3.days.ago) diff --git a/spec/fixtures/grafana/dashboard_response.json b/spec/fixtures/grafana/dashboard_response.json deleted file mode 100644 index c0dd77e2fdcbd6e5590ddccb15b8b4c6ea638ba3..0000000000000000000000000000000000000000 --- a/spec/fixtures/grafana/dashboard_response.json +++ /dev/null @@ -1,764 +0,0 @@ -{ - "meta": { - "type": "db", - "canSave": true, - "canEdit": true, - "canAdmin": true, - "canStar": true, - "slug": "gitlab-omnibus-redis", - "url": "/-/grafana/d/XDaNK6amz/gitlab-omnibus-redis", - "expires": "0001-01-01T00:00:00Z", - "created": "2019-10-04T13:43:20Z", - "updated": "2019-10-04T13:43:20Z", - "updatedBy": "Anonymous", - "createdBy": "Anonymous", - "version": 1, - "hasAcl": false, - "isFolder": false, - "folderId": 1, - "folderTitle": "GitLab Omnibus", - "folderUrl": "/-/grafana/dashboards/f/l2EpNh2Zk/gitlab-omnibus", - "provisioned": true, - "provisionedExternalId": "redis.json" - }, - "dashboard": { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations \u0026 Alerts", - "type": "dashboard" - } - ] - }, - "description": "GitLab Omnibus dashboard for Redis servers", - "editable": true, - "gnetId": 763, - "graphTooltip": 0, - "id": 3, - "iteration": 1556027798221, - "links": [], - "panels": [ - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - "datasource": "GitLab Omnibus", - "decimals": 0, - "editable": true, - "error": false, - "format": "dtdurations", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { "h": 3, "w": 4, "x": 0, "y": 0 }, - "id": 9, - "interval": null, - "isNew": true, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { "name": "value to text", "value": 1 }, - { "name": "range to text", "value": 2 } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ "from": "null", "text": "N/A", "to": "null" }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "addr", - "targets": [ - { - "expr": "avg(time() - redis_start_time_seconds{instance=~\"$instance\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 1800 - } - ], - "thresholds": "", - "title": "Uptime", - "type": "singlestat", - "valueFontSize": "70%", - "valueMaps": [{ "op": "=", "text": "N/A", "value": "null" }], - "valueName": "current" - }, - { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - "datasource": "GitLab Omnibus", - "decimals": 0, - "editable": true, - "error": false, - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { "h": 3, "w": 4, "x": 4, "y": 0 }, - "hideTimeOverride": true, - "id": 12, - "interval": null, - "isNew": true, - "links": [], - "mappingType": 1, - "mappingTypes": [ - { "name": "value to text", "value": 1 }, - { "name": "range to text", "value": 2 } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ "from": "null", "text": "N/A", "to": "null" }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": true - }, - "tableColumn": "", - "targets": [ - { - "expr": "sum(\n avg_over_time(redis_connected_clients{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "", - "metric": "", - "refId": "A", - "step": 2 - } - ], - "thresholds": "", - "timeFrom": "1m", - "timeShift": null, - "title": "Clients", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [{ "op": "=", "text": "N/A", "value": "null" }], - "valueName": "avg" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "gridPos": { "h": 6, "w": 8, "x": 8, "y": 0 }, - "id": 2, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(\n rate(redis_commands_processed_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "", - "metric": "A", - "refId": "A", - "step": 240, - "target": "" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Commands Executed", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "reqps", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "decimals": 2, - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "gridPos": { "h": 6, "w": 8, "x": 16, "y": 0 }, - "id": 1, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": true, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(\n rate(redis_keyspace_hits_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "hide": false, - "interval": "1m", - "intervalFactor": 1, - "legendFormat": "hits", - "metric": "", - "refId": "A", - "step": 240, - "target": "" - }, - { - "expr": "sum(\n rate(redis_keyspace_misses_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "hide": false, - "interval": "1m", - "intervalFactor": 1, - "legendFormat": "misses", - "metric": "", - "refId": "B", - "step": 240, - "target": "" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Hits, Misses per Second", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "short", "label": "", "logBase": 1, "max": null, "min": 0, "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": { "max": "#BF1B00" }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "gridPos": { "h": 10, "w": 8, "x": 0, "y": 3 }, - "id": 7, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "null as zero", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [{ "alias": "/max - .*/", "dashes": true }], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "redis_memory_used_bytes{instance=~\"$instance\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "used - {{instance}}", - "metric": "", - "refId": "A", - "step": 240, - "target": "" - }, - { - "expr": "redis_config_maxmemory{instance=~\"$instance\"} \u003e 0", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "max - {{instance}}", - "refId": "B", - "step": 240 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Memory Usage", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "bytes", "label": null, "logBase": 1, "max": null, "min": 0, "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": { - "evicts": "#890F02", - "memcached_items_evicted_total{instance=\"172.17.0.1:9150\",job=\"prometheus\"}": "#890F02", - "reclaims": "#3F6833" - }, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "gridPos": { "h": 7, "w": 8, "x": 8, "y": 6 }, - "id": 8, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [{ "alias": "reclaims", "yaxis": 2 }], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(rate(redis_expired_keys_total{instance=~\"$instance\"}[$__interval]))", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "expired - {{ test_attribute }}", - "metric": "", - "refId": "A", - "step": 240, - "target": "" - }, - { - "expr": "sum(rate(redis_evicted_keys_total{instance=~\"$instance\"}[$__interval]))", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "evicted", - "refId": "B", - "step": 240 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Expired / Evicted", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "cumulative" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "gridPos": { "h": 7, "w": 8, "x": 16, "y": 6 }, - "id": 10, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(\n rate(redis_net_input_bytes_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "In", - "refId": "A", - "step": 240 - }, - { - "expr": "sum(\n rate(redis_net_output_bytes_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "Out", - "refId": "B", - "step": 240 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Network I/O", - "tooltip": { "msResolution": true, "shared": true, "sort": 0, "value_type": "cumulative" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "Bps", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 8, - "grid": {}, - "gridPos": { "h": 7, "w": 16, "x": 0, "y": 13 }, - "id": 14, - "isNew": true, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum without (instance) (\n rate(redis_commands_total{instance=~\"$instance\"}[$__interval])\n) \u003e 0", - "format": "time_series", - "interval": "1m", - "intervalFactor": 2, - "legendFormat": "{{ cmd }}", - "metric": "redis_command_calls_total", - "refId": "A", - "step": 240 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Command Calls / sec", - "tooltip": { "msResolution": true, "shared": true, "sort": 2, "value_type": "individual" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 7, - "grid": {}, - "gridPos": { "h": 7, "w": 8, "x": 16, "y": 13 }, - "id": 13, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum(redis_db_keys{instance=~\"$instance\"} - redis_db_keys_expiring{instance=~\"$instance\"}) ", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "not expiring", - "refId": "A", - "step": 240, - "target": "" - }, - { - "expr": "sum(redis_db_keys_expiring{instance=~\"$instance\"})", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "expiring", - "metric": "", - "refId": "B", - "step": 240 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Expiring vs Not-Expiring Keys", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "short", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "GitLab Omnibus", - "editable": true, - "error": false, - "fill": 7, - "grid": {}, - "gridPos": { "h": 7, "w": 16, "x": 0, "y": 20 }, - "id": 5, - "isNew": true, - "legend": { - "alignAsTable": true, - "avg": false, - "current": true, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "paceLength": 10, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum by (db) (\n redis_db_keys{instance=~\"$instance\"}\n)", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{ db }} ", - "refId": "A", - "step": 240, - "target": "" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Items per DB", - "tooltip": { "msResolution": false, "shared": true, "sort": 0, "value_type": "individual" }, - "type": "graph", - "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, - "yaxes": [ - { "format": "none", "label": null, "logBase": 1, "max": null, "min": "0", "show": true }, - { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } - ], - "yaxis": { "align": false, "alignLevel": null } - } - ], - "refresh": "1m", - "schemaVersion": 18, - "style": "dark", - "tags": ["redis"], - "templating": { - "list": [ - { - "allValue": null, - "current": { "tags": [], "text": "All", "value": "$__all" }, - "datasource": "GitLab Omnibus", - "definition": "", - "hide": 0, - "includeAll": true, - "label": null, - "multi": false, - "name": "instance", - "options": [], - "query": "label_values(up{job=\"redis\"}, instance)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { "from": "now-24h", "to": "now" }, - "timepicker": { - "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], - "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] - }, - "timezone": "", - "title": "GitLab Omnibus - Redis", - "uid": "XDaNK6amz", - "version": 1 - } -} diff --git a/spec/fixtures/grafana/datasource_response.json b/spec/fixtures/grafana/datasource_response.json deleted file mode 100644 index 07c075beb3565d8dab7b966681fb450323e94777..0000000000000000000000000000000000000000 --- a/spec/fixtures/grafana/datasource_response.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "id": 1, - "orgId": 1, - "name": "GitLab Omnibus", - "type": "prometheus", - "typeLogoUrl": "", - "access": "proxy", - "url": "http://localhost:9090", - "password": "", - "user": "", - "database": "", - "basicAuth": false, - "basicAuthUser": "", - "basicAuthPassword": "", - "withCredentials": false, - "isDefault": true, - "jsonData": {}, - "secureJsonFields": {}, - "version": 1, - "readOnly": true -} diff --git a/spec/fixtures/grafana/expected_grafana_embed.json b/spec/fixtures/grafana/expected_grafana_embed.json deleted file mode 100644 index 0cee03858862428bac3a94a4d45e4cfca5f24e6e..0000000000000000000000000000000000000000 --- a/spec/fixtures/grafana/expected_grafana_embed.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "panel_groups": [ - { - "panels": [ - { - "title": "Network I/O", - "type": "area-chart", - "y_label": "", - "metrics": [ - { - "id": "In_0", - "query_range": "sum( rate(redis_net_input_bytes_total{instance=~\"localhost:9121\"}[1m]))", - "label": "In" - }, - { - "id": "Out_1", - "query_range": "sum( rate(redis_net_output_bytes_total{instance=~\"localhost:9121\"}[1m]))", - "label": "Out" - } - ] - } - ] - } - ] -} diff --git a/spec/fixtures/grafana/proxy_response.json b/spec/fixtures/grafana/proxy_response.json deleted file mode 100644 index b9f34abcaaf06c2db44efb7370e6bac6925dc2dd..0000000000000000000000000000000000000000 --- a/spec/fixtures/grafana/proxy_response.json +++ /dev/null @@ -1,459 +0,0 @@ -{ - "status": "success", - "data": { - "resultType": "matrix", - "result": [ - { - "metric": { - "test_attribute": "test-attribute-value" - }, - "values": [ - [1570768177, "54"], - [1570768237, "54"], - [1570768297, "54"], - [1570768357, "54"], - [1570768417, "54"], - [1570768477, "54"], - [1570768537, "54"], - [1570768597, "54"], - [1570768657, "54"], - [1570768717, "54"], - [1570768777, "54"], - [1570768837, "54"], - [1570768897, "54"], - [1570768957, "54"], - [1570769017, "54"], - [1570769077, "54"], - [1570769377, "54"], - [1570769437, "54"], - [1570769497, "54"], - [1570769557, "54"], - [1570769617, "54"], - [1570769677, "54"], - [1570769737, "54"], - [1570769797, "54"], - [1570769857, "54"], - [1570769917, "54"], - [1570769977, "54"], - [1570770037, "54"], - [1570770097, "54"], - [1570770157, "54"], - [1570770217, "54"], - [1570770277, "54"], - [1570770337, "54"], - [1570770397, "54"], - [1570770457, "54"], - [1570770517, "54"], - [1570770577, "54"], - [1570770637, "54"], - [1570770697, "54"], - [1570770757, "54"], - [1570770817, "54"], - [1570770877, "54"], - [1570770937, "54"], - [1570770997, "54"], - [1570771057, "54"], - [1570771117, "54"], - [1570771177, "54"], - [1570771237, "54"], - [1570771297, "54"], - [1570771357, "54"], - [1570771417, "54"], - [1570771477, "54"], - [1570771537, "54"], - [1570771597, "54"], - [1570771657, "54"], - [1570771717, "54"], - [1570771777, "54"], - [1570771837, "54"], - [1570771897, "54"], - [1570771957, "54"], - [1570772017, "54"], - [1570772077, "54"], - [1570772137, "54"], - [1570772197, "54"], - [1570772257, "54"], - [1570772317, "54"], - [1570772377, "54"], - [1570772437, "54"], - [1570772497, "54"], - [1570772557, "54"], - [1570772617, "54"], - [1570772677, "54"], - [1570772737, "54"], - [1570772797, "54"], - [1570772857, "54"], - [1570772917, "54"], - [1570772977, "54"], - [1570773037, "54"], - [1570773097, "54"], - [1570773157, "54"], - [1570773217, "54"], - [1570773277, "54"], - [1570773337, "54"], - [1570773397, "54"], - [1570773457, "54"], - [1570773517, "54"], - [1570773577, "54"], - [1570773637, "54"], - [1570773697, "54"], - [1570773757, "54"], - [1570773817, "54"], - [1570773877, "54"], - [1570773937, "54"], - [1570773997, "54"], - [1570774057, "54"], - [1570774117, "54"], - [1570774177, "54"], - [1570774237, "54"], - [1570774297, "54"], - [1570774357, "54"], - [1570774417, "54"], - [1570774477, "54"], - [1570774537, "54"], - [1570774597, "54"], - [1570774657, "54"], - [1570774717, "54"], - [1570774777, "54"], - [1570774837, "54"], - [1570774897, "54"], - [1570774957, "54"], - [1570775017, "54"], - [1570775077, "54"], - [1570775137, "54"], - [1570776937, "54"], - [1570776997, "54"], - [1570777057, "54"], - [1570777117, "54"], - [1570777177, "54"], - [1570777237, "54"], - [1570777297, "54"], - [1570777357, "54"], - [1570777417, "54"], - [1570777477, "54"], - [1570777537, "54"], - [1570777597, "54"], - [1570777657, "54"], - [1570777717, "54"], - [1570778017, "54"], - [1570778077, "54"], - [1570778137, "54"], - [1570778197, "54"], - [1570778257, "54"], - [1570778317, "54"], - [1570778377, "54"], - [1570778437, "54"], - [1570778497, "54"], - [1570778557, "54"], - [1570778617, "54"], - [1570778677, "54"], - [1570778737, "54"], - [1570778797, "54"], - [1570778857, "54"], - [1570778917, "54"], - [1570778977, "54"], - [1570779037, "54"], - [1570779097, "54"], - [1570779157, "54"], - [1570779217, "54"], - [1570779277, "54"], - [1570779337, "54"], - [1570779397, "54"], - [1570779457, "54"], - [1570779517, "54"], - [1570779577, "54"], - [1570779637, "54"], - [1570779697, "54"], - [1570779757, "54"], - [1570779817, "54"], - [1570779877, "54"], - [1570779937, "54"], - [1570779997, "54"], - [1570780057, "54"], - [1570780117, "54"], - [1570780177, "54"], - [1570780237, "54"], - [1570780297, "54"], - [1570780357, "54"], - [1570780417, "54"], - [1570780477, "54"], - [1570780537, "54"], - [1570780597, "54"], - [1570780657, "54"], - [1570780717, "54"], - [1570780777, "54"], - [1570780837, "54"], - [1570780897, "54"], - [1570780957, "54"], - [1570781017, "54"], - [1570781077, "54"], - [1570781137, "54"], - [1570781197, "54"], - [1570781257, "54"], - [1570781317, "54"], - [1570781377, "54"], - [1570781437, "54"], - [1570781497, "54"], - [1570781557, "54"], - [1570781617, "54"], - [1570781677, "54"], - [1570781737, "54"], - [1570781797, "54"], - [1570781857, "54"], - [1570781917, "54"], - [1570781977, "54"], - [1570782037, "54"], - [1570782097, "54"], - [1570782157, "54"], - [1570782217, "54"], - [1570782277, "54"], - [1570782337, "54"], - [1570782397, "54"], - [1570782457, "54"], - [1570782517, "54"], - [1570782577, "54"], - [1570782637, "54"], - [1570782697, "54"], - [1570782757, "54"], - [1570782817, "54"], - [1570782877, "54"], - [1570782937, "54"], - [1570782997, "54"], - [1570783057, "54"], - [1570783117, "54"], - [1570783177, "54"], - [1570783237, "54"], - [1570783297, "54"], - [1570783357, "54"], - [1570783417, "54"], - [1570783477, "54"], - [1570783537, "54"], - [1570783597, "54"], - [1570783657, "54"], - [1570783717, "54"], - [1570783777, "54"], - [1570783837, "54"], - [1570783897, "54"], - [1570783957, "54"], - [1570784017, "54"], - [1570784077, "54"], - [1570784137, "54"], - [1570784197, "54"], - [1570784257, "54"], - [1570784317, "54"], - [1570784377, "54"], - [1570784437, "54"], - [1570784497, "54"], - [1570784557, "54"], - [1570784617, "54"], - [1570784677, "54"], - [1570784737, "54"], - [1570784797, "54"], - [1570784857, "54"], - [1570784917, "54"], - [1570784977, "54"], - [1570785037, "54"], - [1570785097, "54"], - [1570785157, "54"], - [1570785217, "54"], - [1570785277, "54"], - [1570785337, "54"], - [1570785397, "54"], - [1570785457, "54"], - [1570785517, "54"], - [1570785577, "54"], - [1570785637, "54"], - [1570785697, "54"], - [1570785757, "54"], - [1570785817, "54"], - [1570785877, "54"], - [1570785937, "54"], - [1570785997, "54"], - [1570786057, "54"], - [1570786117, "54"], - [1570786177, "54"], - [1570786237, "54"], - [1570786297, "54"], - [1570786357, "54"], - [1570786417, "54"], - [1570786477, "54"], - [1570786537, "54"], - [1570786597, "54"], - [1570786657, "54"], - [1570786717, "54"], - [1570786777, "54"], - [1570786837, "54"], - [1570786897, "54"], - [1570786957, "53"], - [1570787017, "54"], - [1570787077, "54"], - [1570787137, "54"], - [1570787197, "54"], - [1570787257, "54"], - [1570787317, "54"], - [1570787377, "54"], - [1570787437, "54"], - [1570787497, "54"], - [1570787557, "54"], - [1570787617, "54"], - [1570787677, "54"], - [1570787737, "54"], - [1570787797, "54"], - [1570787857, "54"], - [1570787917, "54"], - [1570787977, "54"], - [1570788037, "54"], - [1570788097, "54"], - [1570788157, "54"], - [1570788217, "54"], - [1570788277, "54"], - [1570788337, "54"], - [1570788397, "54"], - [1570788457, "54"], - [1570788517, "54"], - [1570788577, "54"], - [1570788637, "54"], - [1570788697, "54"], - [1570788757, "54"], - [1570788817, "54"], - [1570788877, "54"], - [1570788937, "54"], - [1570788997, "54"], - [1570789057, "54"], - [1570789117, "54"], - [1570789177, "54"], - [1570789237, "54"], - [1570789297, "54"], - [1570789357, "54"], - [1570789417, "54"], - [1570789477, "54"], - [1570789537, "54"], - [1570789597, "54"], - [1570789657, "54"], - [1570789717, "54"], - [1570789777, "54"], - [1570789837, "54"], - [1570789897, "54"], - [1570789957, "54"], - [1570790017, "54"], - [1570790077, "54"], - [1570790137, "54"], - [1570790197, "54"], - [1570790257, "54"], - [1570790317, "54"], - [1570790377, "54"], - [1570790437, "54"], - [1570790497, "54"], - [1570790557, "54"], - [1570790617, "54"], - [1570790677, "54"], - [1570790737, "54"], - [1570790797, "54"], - [1570790857, "54"], - [1570790917, "54"], - [1570790977, "54"], - [1570791037, "54"], - [1570791097, "54"], - [1570791157, "54"], - [1570791217, "54"], - [1570791277, "54"], - [1570791337, "54"], - [1570791397, "54"], - [1570791457, "54"], - [1570791517, "54"], - [1570791577, "54"], - [1570791637, "54"], - [1570791697, "54"], - [1570791757, "54"], - [1570791817, "54"], - [1570791877, "54"], - [1570791937, "54"], - [1570791997, "54"], - [1570792057, "54"], - [1570792117, "54"], - [1570792177, "54"], - [1570792237, "54"], - [1570792297, "54"], - [1570792357, "54"], - [1570792417, "54"], - [1570792477, "54"], - [1570792537, "54"], - [1570792597, "54"], - [1570792657, "54"], - [1570792717, "54"], - [1570792777, "54"], - [1570792837, "54"], - [1570792897, "54"], - [1570792957, "54"], - [1570793017, "54"], - [1570793077, "54"], - [1570793137, "54"], - [1570793197, "54"], - [1570793257, "54"], - [1570793317, "54"], - [1570793377, "54"], - [1570793437, "54"], - [1570793497, "54"], - [1570793557, "54"], - [1570793617, "54"], - [1570793677, "54"], - [1570793737, "54"], - [1570793797, "54"], - [1570793857, "54"], - [1570793917, "54"], - [1570793977, "54"], - [1570794037, "54"], - [1570794097, "54"], - [1570794157, "54"], - [1570794217, "54"], - [1570794277, "54"], - [1570794337, "54"], - [1570794397, "54"], - [1570794457, "54"], - [1570794517, "54"], - [1570794577, "54"], - [1570794637, "54"], - [1570794697, "54"], - [1570794757, "54"], - [1570794817, "54"], - [1570794877, "54"], - [1570794937, "54"], - [1570794997, "54"], - [1570795057, "54"], - [1570795117, "54"], - [1570795177, "54"], - [1570795237, "54"], - [1570795297, "54"], - [1570795357, "54"], - [1570795417, "54"], - [1570795477, "54"], - [1570795537, "54"], - [1570795597, "54"], - [1570795657, "54"], - [1570795717, "54"], - [1570795777, "54"], - [1570795837, "54"], - [1570795897, "54"], - [1570795957, "54"], - [1570796017, "54"], - [1570796077, "54"], - [1570796137, "54"], - [1570796197, "54"], - [1570796257, "54"], - [1570796317, "54"], - [1570796377, "54"], - [1570796437, "55"], - [1570796497, "54"], - [1570796557, "54"], - [1570796617, "54"], - [1570796677, "54"], - [1570796737, "54"], - [1570796797, "54"], - [1570796857, "54"], - [1570796917, "54"], - [1570796977, "54"] - ] - } - ] - } -} diff --git a/spec/fixtures/grafana/simplified_dashboard_response.json b/spec/fixtures/grafana/simplified_dashboard_response.json deleted file mode 100644 index b450fda082b257938ed46120b17f519141fe457e..0000000000000000000000000000000000000000 --- a/spec/fixtures/grafana/simplified_dashboard_response.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "dashboard": { - "panels": [ - { - "datasource": "GitLab Omnibus", - "id": 8, - "lines": true, - "targets": [ - { - "expr": "sum(\n rate(redis_net_input_bytes_total{instance=~\"$instance\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "legendFormat": "In", - "refId": "A" - }, - { - "expr": "sum(\n rate(redis_net_output_bytes_total{instance=~\"[[instance]]\"}[$__interval])\n)", - "format": "time_series", - "interval": "1m", - "legendFormat": "Out", - "refId": "B" - } - ], - "title": "Network I/O", - "type": "graph", - "yaxes": [{ "format": "Bps" }, { "format": "short" }] - } - ], - "templating": { - "list": [ - { - "current": { - "value": "localhost:9121" - }, - "name": "instance" - } - ] - } - } -} diff --git a/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb b/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb deleted file mode 100644 index 546b85925468f0913f25ce9b25255be1338b4d51..0000000000000000000000000000000000000000 --- a/spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Resolvers::Projects::GrafanaIntegrationResolver do - include GraphqlHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:current_user) { create(:user) } - let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } - - describe '#resolve' do - context 'when object is not a project' do - it { expect(resolve_integration(obj: current_user)).to eq nil } - end - - context 'when object is a project' do - it { expect(resolve_integration(obj: project)).to eq grafana_integration } - end - - context 'when object is nil' do - it { expect(resolve_integration(obj: nil)).to eq nil } - end - end - - def resolve_integration(obj: project, context: { current_user: current_user }) - resolve(described_class, obj: obj, ctx: context) - end -end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 7ce3f4c675ce19466f45bc5a55758d110d78e444..ddece705ebe612b8fcc34b0ea73f86d3afa56bbd 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -405,7 +405,7 @@ subject { described_class.fields['grafanaIntegration'] } it { is_expected.to have_graphql_type(Types::GrafanaIntegrationType) } - it { is_expected.to have_graphql_resolver(Resolvers::Projects::GrafanaIntegrationResolver) } + it { is_expected.to have_graphql_resolver(nil) } end describe 'environments field' do diff --git a/spec/lib/gitlab/doctor/secrets_spec.rb b/spec/lib/gitlab/doctor/secrets_spec.rb index 64995298bf29dadce77da6fe728a3d23a5f9f08c..f5d9e20f16722a3931568d1b83620fc1e7961641 100644 --- a/spec/lib/gitlab/doctor/secrets_spec.rb +++ b/spec/lib/gitlab/doctor/secrets_spec.rb @@ -6,7 +6,6 @@ let!(:user) { create(:user, otp_secret: "test") } let!(:group) { create(:group, :allow_runner_registration_token, runners_token: "test") } let!(:project) { create(:project) } - let!(:grafana_integration) { create(:grafana_integration, project: project, token: "test") } let!(:integration) { create(:integration, project: project, properties: { test_key: "test_value" }) } let!(:webhook) { create(:project_hook, project: project) } let(:logger) { instance_double(Logger).as_null_object } @@ -105,14 +104,6 @@ end end - context 'when GrafanaIntegration token is set via private method' do - it 'can access GrafanaIntegration token value' do - expect(logger).to receive(:info).with(/GrafanaIntegration failures: 0/) - - doctor_secrets - end - end - context 'when secrets doctor is called' do it 'meets the necessary Ci::Build prerequisites' do subj = described_class.new(logger) diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 99095ac909c317fceeb023bb909f82e2a7bf010f..af76636d8f1fb9a41123d5b8293ef305eba0fc4c 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -831,7 +831,6 @@ project: - designs - project_aliases - external_pull_requests -- grafana_integration - remove_source_branch_after_merge - deleting_user - upstream_projects diff --git a/spec/lib/grafana/client_spec.rb b/spec/lib/grafana/client_spec.rb deleted file mode 100644 index 13fe9acc6e9127d2c91ebcd7c1848da8dad594ff..0000000000000000000000000000000000000000 --- a/spec/lib/grafana/client_spec.rb +++ /dev/null @@ -1,131 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Grafana::Client do - let(:grafana_url) { 'https://grafanatest.com/-/grafana-project' } - let(:token) { 'test-token' } - - subject(:client) { described_class.new(api_url: grafana_url, token: token) } - - shared_examples 'calls grafana api' do - let!(:grafana_api_request) { stub_grafana_request(grafana_api_url) } - - it 'calls grafana api' do - subject - - expect(grafana_api_request).to have_been_requested - end - end - - shared_examples 'no redirects' do - let(:redirect_to) { 'https://redirected.example.com' } - let(:other_url) { 'https://grafana.example.org' } - - let!(:redirected_req_stub) { stub_grafana_request(other_url) } - - let!(:redirect_req_stub) do - stub_grafana_request( - grafana_api_url, - status: 302, - headers: { location: redirect_to } - ) - end - - it 'does not follow redirects' do - expect { subject }.to raise_exception( - Grafana::Client::Error, - 'Grafana response status code: 302, Message: {}' - ) - - expect(redirect_req_stub).to have_been_requested - expect(redirected_req_stub).not_to have_been_requested - end - end - - shared_examples 'handles exceptions' do - exceptions = { - Gitlab::HTTP::Error => 'Error when connecting to Grafana', - Net::OpenTimeout => 'Connection to Grafana timed out', - SocketError => 'Received SocketError when trying to connect to Grafana', - OpenSSL::SSL::SSLError => 'Grafana returned invalid SSL data', - Errno::ECONNREFUSED => 'Connection refused', - StandardError => 'Grafana request failed due to StandardError' - } - - exceptions.each do |exception, message| - context exception.to_s do - before do - stub_request(:get, grafana_api_url).to_raise(exception) - end - - it do - expect { subject } - .to raise_exception(Grafana::Client::Error, message) - end - end - end - end - - describe '#get_dashboard' do - let(:grafana_api_url) { 'https://grafanatest.com/-/grafana-project/api/dashboards/uid/FndfgnX' } - - subject do - client.get_dashboard(uid: 'FndfgnX') - end - - it_behaves_like 'calls grafana api' - it_behaves_like 'no redirects' - it_behaves_like 'handles exceptions' - end - - describe '#get_datasource' do - let(:grafana_api_url) { 'https://grafanatest.com/-/grafana-project/api/datasources/name/Test%20Name' } - - subject do - client.get_datasource(name: 'Test Name') - end - - it_behaves_like 'calls grafana api' - it_behaves_like 'no redirects' - it_behaves_like 'handles exceptions' - end - - describe '#proxy_datasource' do - let(:grafana_api_url) do - 'https://grafanatest.com/-/grafana-project/' \ - 'api/datasources/proxy/' \ - '1/api/v1/query_range' \ - '?query=rate(relevant_metric)' \ - '&start=1570441248&end=1570444848&step=900' - end - - subject do - client.proxy_datasource( - datasource_id: '1', - proxy_path: 'api/v1/query_range', - query: { - query: 'rate(relevant_metric)', - start: 1570441248, - end: 1570444848, - step: 900 - } - ) - end - - it_behaves_like 'calls grafana api' - it_behaves_like 'no redirects' - it_behaves_like 'handles exceptions' - end - - private - - def stub_grafana_request(url, body: {}, status: 200, headers: {}) - stub_request(:get, url) - .to_return( - status: status, - headers: { 'Content-Type' => 'application/json' }.merge(headers), - body: body.to_json - ) - end -end diff --git a/spec/lib/grafana/time_window_spec.rb b/spec/lib/grafana/time_window_spec.rb deleted file mode 100644 index 0657bed7b28b69cf986b6288952694e47ac17655..0000000000000000000000000000000000000000 --- a/spec/lib/grafana/time_window_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Grafana::TimeWindow do - let(:from) { '1552799400000' } - let(:to) { '1552828200000' } - - around do |example| - travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run } - end - - describe '#formatted' do - subject { described_class.new(from, to).formatted } - - it { is_expected.to eq(start: "2019-03-17T05:10:00Z", end: "2019-03-17T13:10:00Z") } - end - - describe '#in_milliseconds' do - subject { described_class.new(from, to).in_milliseconds } - - it { is_expected.to eq(from: 1552799400000, to: 1552828200000) } - - context 'when non-unix parameters are provided' do - let(:to) { Time.now.to_s } - - let(:default_from) { 8.hours.ago.to_i * 1000 } - let(:default_to) { Time.now.to_i * 1000 } - - it { is_expected.to eq(from: default_from, to: default_to) } - end - end -end - -RSpec.describe Grafana::RangeWithDefaults do - let(:from) { Grafana::Timestamp.from_ms_since_epoch('1552799400000') } - let(:to) { Grafana::Timestamp.from_ms_since_epoch('1552828200000') } - - around do |example| - travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run } - end - - describe '#to_hash' do - subject { described_class.new(from: from, to: to).to_hash } - - it { is_expected.to eq(from: from, to: to) } - - context 'when only "to" is provided' do - let(:from) { nil } - - it 'has the expected properties' do - expect(subject[:to]).to eq(to) - expect(subject[:from].time).to eq(to.time - 8.hours) - end - end - - context 'when only "from" is provided' do - let(:to) { nil } - - it 'has the expected properties' do - expect(subject[:to].time).to eq(from.time + 8.hours) - expect(subject[:from]).to eq(from) - end - end - - context 'when no parameters are provided' do - let(:to) { nil } - let(:from) { nil } - - let(:default_from) { 8.hours.ago } - let(:default_to) { Time.now } - - it 'has the expected properties' do - expect(subject[:to].time).to eq(default_to) - expect(subject[:from].time).to eq(default_from) - end - end - end -end - -RSpec.describe Grafana::Timestamp do - let(:timestamp) { Time.at(1552799400) } - - around do |example| - travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run } - end - - describe '#formatted' do - subject { described_class.new(timestamp).formatted } - - it { is_expected.to eq "2019-03-17T05:10:00Z" } - end - - describe '#to_ms' do - subject { described_class.new(timestamp).to_ms } - - it { is_expected.to eq 1552799400000 } - end - - describe '.from_ms_since_epoch' do - let(:timestamp) { '1552799400000' } - - subject { described_class.from_ms_since_epoch(timestamp) } - - it { is_expected.to be_a described_class } - - context 'when the input is not a unix-ish timestamp' do - let(:timestamp) { Time.now.to_s } - - it 'raises an error' do - expect { subject }.to raise_error(Grafana::Timestamp::Error) - end - end - end -end diff --git a/spec/lib/grafana/validator_spec.rb b/spec/lib/grafana/validator_spec.rb deleted file mode 100644 index b45749ffc95cd3edbcee6208b21306ae449f496b..0000000000000000000000000000000000000000 --- a/spec/lib/grafana/validator_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Grafana::Validator do - let(:grafana_dashboard) { Gitlab::Json.parse(fixture_file('grafana/simplified_dashboard_response.json'), symbolize_names: true) } - let(:datasource) { Gitlab::Json.parse(fixture_file('grafana/datasource_response.json'), symbolize_names: true) } - let(:panel) { grafana_dashboard[:dashboard][:panels].first } - - let(:query_params) do - { - from: '1570397739557', - to: '1570484139557', - panelId: '8', - 'var-instance': 'localhost:9121' - } - end - - describe 'validate!' do - shared_examples_for 'processing error' do |message| - it 'raises a processing error' do - expect { subject } - .to raise_error(::Grafana::Validator::Error, message) - end - end - - subject { described_class.new(grafana_dashboard, datasource, panel, query_params).validate! } - - it 'does not raise an error' do - expect { subject }.not_to raise_error - end - - context 'when query param "from" is not specified' do - before do - query_params.delete(:from) - end - - it_behaves_like 'processing error', 'Grafana query parameters must include from and to.' - end - - context 'when query param "to" is not specified' do - before do - query_params.delete(:to) - end - - it_behaves_like 'processing error', 'Grafana query parameters must include from and to.' - end - - context 'when the panel is not provided' do - let(:panel) { nil } - - it_behaves_like 'processing error', 'Panel type must be a line graph.' - end - - context 'when the panel is not a graph' do - before do - panel[:type] = 'singlestat' - end - - it_behaves_like 'processing error', 'Panel type must be a line graph.' - end - - context 'when the panel is not a line graph' do - before do - panel[:lines] = false - end - - it_behaves_like 'processing error', 'Panel type must be a line graph.' - end - - context 'when the query dashboard includes undefined variables' do - before do - query_params.delete(:'var-instance') - end - - it_behaves_like 'processing error', 'All Grafana variables must be defined in the query parameters.' - end - - context 'when the expression contains unsupported global variables' do - before do - grafana_dashboard[:dashboard][:panels][0][:targets][0][:expr] = 'sum(important_metric[$__interval_ms])' - end - - it_behaves_like 'processing error', "Prometheus must not include #{described_class::UNSUPPORTED_GRAFANA_GLOBAL_VARS}" - end - - context 'when the datasource is not proxyable' do - before do - datasource[:access] = 'not-proxy' - end - - it_behaves_like 'processing error', 'Only Prometheus datasources with proxy access in Grafana are supported.' - end - - # Skipping datasource validation allows for checks to be - # run without a secondary call to Grafana API - context 'when the datasource is not provided' do - let(:datasource) { nil } - - it 'does not raise an error' do - expect { subject }.not_to raise_error - end - end - end - - describe 'valid?' do - subject { described_class.new(grafana_dashboard, datasource, panel, query_params).valid? } - - context 'with valid arguments' do - it { is_expected.to be true } - end - - context 'with invalid arguments' do - let(:query_params) { {} } - - it { is_expected.to be false } - end - end -end diff --git a/spec/migrations/20250725071156_remove_grafana_integrations_fk_project_id_spec.rb b/spec/migrations/20250725071156_remove_grafana_integrations_fk_project_id_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..109aeb2747990c93f068576345fe69b250c5f03c --- /dev/null +++ b/spec/migrations/20250725071156_remove_grafana_integrations_fk_project_id_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveGrafanaIntegrationsFkProjectId, feature_category: :observability do + include Database::TableSchemaHelpers + + let(:table_name) { :grafana_integrations } + + it 'drops the projects foreign key constraint' do + reversible_migration do |migration| + migration.before -> { + expect_foreign_key_to_exist(table_name, described_class::CONSTRAINT_NAME) + } + + migration.after -> { + expect_foreign_key_not_to_exist(table_name, described_class::CONSTRAINT_NAME) + } + end + end +end diff --git a/spec/migrations/20250725071302_remove_grafana_integrations_spec.rb b/spec/migrations/20250725071302_remove_grafana_integrations_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3f043b7d0f0dbc17cc7a3689786fea36daae2e55 --- /dev/null +++ b/spec/migrations/20250725071302_remove_grafana_integrations_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveGrafanaIntegrations, feature_category: :observability do + include Database::TableSchemaHelpers + + let(:table_name) { :grafana_integrations } + let(:column_attributes) do + [ + { name: 'id', sql_type: 'bigint', null: false, default: nil }, + { name: 'project_id', sql_type: 'bigint', null: false, default: nil }, + { name: 'created_at', sql_type: 'timestamp with time zone', null: false, default: nil }, + { name: 'updated_at', sql_type: 'timestamp with time zone', null: false, default: nil }, + { name: 'encrypted_token', sql_type: 'character varying(255)', null: false, default: nil }, + { name: 'encrypted_token_iv', sql_type: 'character varying(255)', null: false, default: nil }, + { name: 'grafana_url', sql_type: 'character varying(1024)', null: false, default: nil }, + { name: 'enabled', sql_type: 'boolean', null: false, default: 'false' } + ] + end + + it 'drops the grafana_integrations table' do + reversible_migration do |migration| + migration.before -> { + expect_table_columns_to_match(column_attributes, table_name) + expect_primary_keys_after_tables([table_name]) + expect_index_to_exist('index_grafana_integrations_on_enabled') + expect_index_to_exist('index_grafana_integrations_on_project_id') + } + + migration.after -> { + expect(connection.table_exists?(table_name)).to be(false) + } + end + end +end diff --git a/spec/models/grafana_integration_spec.rb b/spec/models/grafana_integration_spec.rb deleted file mode 100644 index 0c7edab699860b666e234ab51d9b0151442c8290..0000000000000000000000000000000000000000 --- a/spec/models/grafana_integration_spec.rb +++ /dev/null @@ -1,123 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe GrafanaIntegration do - describe 'associations' do - it { is_expected.to belong_to(:project) } - end - - describe 'validations' do - it { is_expected.to validate_presence_of(:project) } - it { is_expected.to validate_presence_of(:encrypted_token) } - - it 'disallows invalid urls for grafana_url' do - unsafe_url = %{https://replaceme.com/'>} - non_ascii_url = 'http://gitlab.com/api/0/projects/project1/something€' - blank_url = '' - excessively_long_url = 'https://grafan' + ('a' * 1024) + '.com' - - is_expected.not_to allow_values( - unsafe_url, - non_ascii_url, - blank_url, - excessively_long_url - ).for(:grafana_url) - end - - it 'allows valid urls for grafana_url' do - external_url = 'http://grafana.com/' - internal_url = 'http://192.168.1.1' - - is_expected.to allow_value( - external_url, - internal_url - ).for(:grafana_url) - end - - it 'disallows non-booleans in enabled column' do - is_expected.not_to allow_value( - nil - ).for(:enabled) - end - - it 'allows booleans in enabled column' do - is_expected.to allow_value( - true, - false - ).for(:enabled) - end - end - - describe '.client' do - subject(:grafana_integration) { create(:grafana_integration) } - - context 'with grafana integration disabled' do - it 'returns a grafana client' do - expect(grafana_integration.client).to be_an_instance_of(::Grafana::Client) - end - end - - context 'with grafana integration enabled' do - it 'returns nil' do - grafana_integration.update!(enabled: false) - - expect(grafana_integration.client).to be_nil - end - end - end - - describe 'attribute encryption' do - subject(:grafana_integration) { create(:grafana_integration, token: 'super-secret') } - - context 'token' do - it 'encrypts original value into encrypted_token attribute' do - expect(grafana_integration.encrypted_token).not_to be_nil - end - - it 'locks access to raw value in private method', :aggregate_failures do - expect { grafana_integration.token }.to raise_error(NoMethodError, /private method .token. called/) - expect(grafana_integration.send(:token)).to eql('super-secret') - end - - it 'prevents overriding token value with its encrypted or masked version', :aggregate_failures do - expect { grafana_integration.update!(token: grafana_integration.encrypted_token) }.not_to change { grafana_integration.reload.send(:token) } - expect { grafana_integration.update!(token: grafana_integration.masked_token) }.not_to change { grafana_integration.reload.send(:token) } - end - end - end - - describe 'Callbacks' do - describe 'before_validation :reset_token' do - context 'when a token was previously set' do - subject(:grafana_integration) { create(:grafana_integration) } - - it 'resets token if url changed' do - grafana_integration.grafana_url = 'http://gitlab1.com' - - expect(grafana_integration).not_to be_valid - expect(grafana_integration.send(:token)).to be_nil - end - - it "does not reset token if new url is set together with the same token" do - grafana_integration.grafana_url = 'http://gitlab_edited.com' - current_token = grafana_integration.send(:token) - grafana_integration.token = current_token - - expect(grafana_integration).to be_valid - expect(grafana_integration.send(:token)).to eq(current_token) - expect(grafana_integration.grafana_url).to eq('http://gitlab_edited.com') - end - - it 'does not reset token if new url is set together with a new token' do - grafana_integration.grafana_url = 'http://gitlab_edited.com' - grafana_integration.token = 'token' - - expect(grafana_integration).to be_valid - expect(grafana_integration.send(:token)).to eq('token') - expect(grafana_integration.grafana_url).to eq('http://gitlab_edited.com') - end - end - end - end -end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 048e77d15df6cae6756a9ca5897fae6882e57e4f..c9bde43cd5f08a85926e93816f1950cc330ac3c3 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -1016,38 +1016,6 @@ def set_access_level(access_level) end end - describe 'read_grafana', feature_category: :observability do - using RSpec::Parameterized::TableSyntax - - let(:policy) { :read_grafana } - - where(:project_visibility, :role, :allowed) do - :public | :anonymous | false - :public | :guest | false - :public | :planner | false - :public | :reporter | true - :internal | :anonymous | false - :internal | :guest | true - :internal | :planner | true - :internal | :reporter | true - :private | :anonymous | false - :private | :guest | true - :private | :planner | true - :private | :reporter | true - end - - with_them do - let(:current_user) { public_send(role) } - let(:project) { public_send("#{project_visibility}_project") } - - if params[:allowed] - it { is_expected.to be_allowed(policy) } - else - it { is_expected.not_to be_allowed(policy) } - end - end - end - describe 'read_prometheus', feature_category: :observability do using RSpec::Parameterized::TableSyntax diff --git a/spec/requests/api/graphql/project/grafana_integration_spec.rb b/spec/requests/api/graphql/project/grafana_integration_spec.rb index eefebd5515b080e16f80690b9d0741c7e7b237bd..e01eafb47c8504c8189b6ddcedb8e93070d34798 100644 --- a/spec/requests/api/graphql/project/grafana_integration_spec.rb +++ b/spec/requests/api/graphql/project/grafana_integration_spec.rb @@ -6,7 +6,6 @@ let_it_be(:project) { create(:project, :repository) } let_it_be(:current_user) { project.first_owner } - let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } let(:fields) do <<~QUERY @@ -22,42 +21,11 @@ ) end - context 'with grafana integration data' do - let(:integration_data) { graphql_data['project']['grafanaIntegration'] } - - context 'without project admin permissions' do - let(:user) { create(:user) } - - before do - project.add_developer(user) - post_graphql(query, current_user: user) - end - - it_behaves_like 'a working graphql query' - - specify { expect(integration_data).to be_nil } - end - - context 'with project admin permissions' do - before do - post_graphql(query, current_user: current_user) - end - - it_behaves_like 'a working graphql query' - - specify { expect(integration_data['grafanaUrl']).to eql grafana_integration.grafana_url } + before do + post_graphql(query, current_user: current_user) + end - specify do - expect( - integration_data['createdAt'] - ).to eql grafana_integration.created_at.strftime('%Y-%m-%dT%H:%M:%SZ') - end + it_behaves_like 'a working graphql query' - specify do - expect( - integration_data['updatedAt'] - ).to eql grafana_integration.updated_at.strftime('%Y-%m-%dT%H:%M:%SZ') - end - end - end + specify { expect(graphql_data['project']['grafanaIntegration']).to be_nil } end diff --git a/spec/support/helpers/grafana_api_helpers.rb b/spec/support/helpers/grafana_api_helpers.rb deleted file mode 100644 index 7a7b6fec5b4107c7111cadd22904270ac619235e..0000000000000000000000000000000000000000 --- a/spec/support/helpers/grafana_api_helpers.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -module GrafanaApiHelpers - def valid_grafana_dashboard_link(base_url) - base_url + - '/d/XDaNK6amz/gitlab-omnibus-redis' \ - '?from=1570397739557&to=1570484139557' \ - '&var-instance=localhost:9121&panelId=8' - end - - def stub_dashboard_request(base_url, path: '/api/dashboards/uid/XDaNK6amz', body: nil) - body ||= fixture_file('grafana/dashboard_response.json') - - stub_request(:get, "#{base_url}#{path}") - .to_return( - status: 200, - body: body, - headers: { 'Content-Type' => 'application/json' } - ) - end - - def stub_datasource_request(base_url, path: '/api/datasources/name/GitLab%20Omnibus', body: nil) - body ||= fixture_file('grafana/datasource_response.json') - - stub_request(:get, "#{base_url}#{path}") - .to_return( - status: 200, - body: body, - headers: { 'Content-Type' => 'application/json' } - ) - end - - def stub_all_grafana_proxy_requests(base_url) - stub_request(:any, %r{#{base_url}/api/datasources/proxy}) - .to_return( - status: 200, - body: fixture_file('grafana/proxy_response.json'), - headers: { 'Content-Type' => 'application/json' } - ) - end -end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index b98dd75e7e0a6c4597cefc1bf53849e92fc98f1e..d755d11f791ff177a21cfc3af88eb897bbda68be 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -3672,7 +3672,6 @@ - './spec/graphql/resolvers/project_packages_resolver_spec.rb' - './spec/graphql/resolvers/project_resolver_spec.rb' - './spec/graphql/resolvers/projects/fork_targets_resolver_spec.rb' -- './spec/graphql/resolvers/projects/grafana_integration_resolver_spec.rb' - './spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb' - './spec/graphql/resolvers/projects_resolver_spec.rb' - './spec/graphql/resolvers/projects/services_resolver_spec.rb' @@ -5591,9 +5590,6 @@ - './spec/lib/gitlab/zoom_link_extractor_spec.rb' - './spec/lib/google_api/auth_spec.rb' - './spec/lib/google_api/cloud_platform/client_spec.rb' -- './spec/lib/grafana/client_spec.rb' -- './spec/lib/grafana/time_window_spec.rb' -- './spec/lib/grafana/validator_spec.rb' - './spec/lib/initializer_connections_spec.rb' - './spec/lib/json_web_token/hmac_token_spec.rb' - './spec/lib/json_web_token/rsa_token_spec.rb' @@ -5957,7 +5953,6 @@ - './spec/models/generic_commit_status_spec.rb' - './spec/models/gpg_key_spec.rb' - './spec/models/gpg_key_subkey_spec.rb' -- './spec/models/grafana_integration_spec.rb' - './spec/models/group/crm_settings_spec.rb' - './spec/models/group_custom_attribute_spec.rb' - './spec/models/group_deploy_keys_group_spec.rb'