summaryrefslogtreecommitdiff
path: root/app/models/clusters
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/clusters')
-rw-r--r--app/models/clusters/agent_token.rb30
-rw-r--r--app/models/clusters/applications/prometheus.rb39
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/cluster.rb16
-rw-r--r--app/models/clusters/clusters_hierarchy.rb2
-rw-r--r--app/models/clusters/concerns/application_status.rb8
-rw-r--r--app/models/clusters/concerns/application_version.rb6
-rw-r--r--app/models/clusters/concerns/prometheus_client.rb50
-rw-r--r--app/models/clusters/integrations/prometheus.rb21
9 files changed, 129 insertions, 45 deletions
diff --git a/app/models/clusters/agent_token.rb b/app/models/clusters/agent_token.rb
index 9d79887b574..d42279502c5 100644
--- a/app/models/clusters/agent_token.rb
+++ b/app/models/clusters/agent_token.rb
@@ -2,17 +2,45 @@
module Clusters
class AgentToken < ApplicationRecord
+ include RedisCacheable
include TokenAuthenticatable
+
add_authentication_token_field :token, encrypted: :required, token_generator: -> { Devise.friendly_token(50) }
+ cached_attr_reader :last_contacted_at
self.table_name = 'cluster_agent_tokens'
+ # The `UPDATE_USED_COLUMN_EVERY` defines how often the token DB entry can be updated
+ UPDATE_USED_COLUMN_EVERY = (40.minutes..55.minutes).freeze
+
belongs_to :agent, class_name: 'Clusters::Agent', optional: false
belongs_to :created_by_user, class_name: 'User', optional: true
before_save :ensure_token
validates :description, length: { maximum: 1024 }
- validates :name, presence: true, length: { maximum: 255 }, on: :create
+ validates :name, presence: true, length: { maximum: 255 }
+
+ def track_usage
+ track_values = { last_used_at: Time.current.utc }
+
+ cache_attributes(track_values)
+
+ # Use update_column so updated_at is skipped
+ update_columns(track_values) if can_update_track_values?
+ end
+
+ private
+
+ def can_update_track_values?
+ # Use a random threshold to prevent beating DB updates.
+ last_used_at_max_age = Random.rand(UPDATE_USED_COLUMN_EVERY)
+
+ real_last_used_at = read_attribute(:last_used_at)
+
+ # Handle too many updates from high token traffic
+ real_last_used_at.nil? ||
+ (Time.current - real_last_used_at) >= last_used_at_max_age
+ end
end
end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index 55a9a0ccb81..b9c136abab4 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Prometheus < ApplicationRecord
- include PrometheusAdapter
+ include ::Clusters::Concerns::PrometheusClient
VERSION = '10.4.1'
@@ -32,7 +32,7 @@ module Clusters
end
state_machine :status do
- after_transition any => [:installed] do |application|
+ after_transition any => [:installed, :externally_installed] do |application|
application.run_after_commit do
Clusters::Applications::ActivateServiceWorker
.perform_async(application.cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
@@ -58,14 +58,6 @@ module Clusters
'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
end
- def service_name
- 'prometheus-prometheus-server'
- end
-
- def service_port
- 80
- end
-
def install_command
helm_command_module::InstallCommand.new(
name: name,
@@ -106,29 +98,6 @@ module Clusters
files.merge('values.yaml': replaced_values)
end
- def prometheus_client
- return unless kube_client
-
- proxy_url = kube_client.proxy_url('service', service_name, service_port, Gitlab::Kubernetes::Helm::NAMESPACE)
-
- # ensures headers containing auth data are appended to original k8s client options
- options = kube_client.rest_client.options
- .merge(prometheus_client_default_options)
- .merge(headers: kube_client.headers)
- Gitlab::PrometheusClient.new(proxy_url, options)
- rescue Kubeclient::HttpError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ENETUNREACH
- # If users have mistakenly set parameters or removed the depended clusters,
- # `proxy_url` could raise an exception because gitlab can not communicate with the cluster.
- # Since `PrometheusAdapter#can_query?` is eargely loaded on environement pages in gitlab,
- # we need to silence the exceptions
- end
-
- def configured?
- kube_client.present? && available?
- rescue Gitlab::UrlBlocker::BlockedUrlError
- false
- end
-
def generate_alert_manager_token!
unless alert_manager_token.present?
update!(alert_manager_token: generate_token)
@@ -146,10 +115,6 @@ module Clusters
.perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
end
- def kube_client
- cluster&.kubeclient&.core_client
- end
-
def install_knative_metrics
return [] unless cluster.application_knative_available?
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 8a49d476ba7..bc80bcd0b06 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.26.0'
+ VERSION = '0.27.0'
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index a34d8a6b98d..a1e2aa194a0 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -51,6 +51,8 @@ module Clusters
has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes', inverse_of: :cluster, autosave: true
+ has_one :integration_prometheus, class_name: 'Clusters::Integrations::Prometheus', inverse_of: :cluster
+
def self.has_one_cluster_application(name) # rubocop:disable Naming/PredicateName
application = APPLICATIONS[name.to_s]
has_one application.association_name, class_name: application.to_s, inverse_of: :cluster # rubocop:disable Rails/ReflectionClassName
@@ -100,7 +102,6 @@ module Clusters
delegate :rbac?, to: :platform_kubernetes, prefix: true, allow_nil: true
delegate :available?, to: :application_helm, prefix: true, allow_nil: true
delegate :available?, to: :application_ingress, prefix: true, allow_nil: true
- delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true
delegate :available?, to: :application_knative, prefix: true, allow_nil: true
delegate :available?, to: :application_elastic_stack, prefix: true, allow_nil: true
delegate :external_ip, to: :application_ingress, prefix: true, allow_nil: true
@@ -148,6 +149,9 @@ module Clusters
scope :with_management_project, -> { where.not(management_project: nil) }
scope :for_project_namespace, -> (namespace_id) { joins(:projects).where(projects: { namespace_id: namespace_id }) }
+
+ # with_application_prometheus scope is deprecated, and scheduled for removal
+ # in %14.0. See https://gitlab.com/groups/gitlab-org/-/epics/4280
scope :with_application_prometheus, -> { includes(:application_prometheus).joins(:application_prometheus) }
scope :with_project_http_integrations, -> (project_ids) do
conditions = { projects: :alert_management_http_integrations }
@@ -276,6 +280,10 @@ module Clusters
public_send(association_name) || public_send("build_#{association_name}") # rubocop:disable GitlabSecurity/PublicSend
end
+ def find_or_build_integration_prometheus
+ integration_prometheus || build_integration_prometheus
+ end
+
def provider
if gcp?
provider_gcp
@@ -361,8 +369,12 @@ module Clusters
end
end
+ def application_prometheus_available?
+ integration_prometheus&.available? || application_prometheus&.available?
+ end
+
def prometheus_adapter
- application_prometheus
+ integration_prometheus || application_prometheus
end
private
diff --git a/app/models/clusters/clusters_hierarchy.rb b/app/models/clusters/clusters_hierarchy.rb
index c9c18d8c96a..125783e6ee1 100644
--- a/app/models/clusters/clusters_hierarchy.rb
+++ b/app/models/clusters/clusters_hierarchy.rb
@@ -16,7 +16,7 @@ module Clusters
model
.unscoped
- .where('clusters.id IS NOT NULL')
+ .where.not('clusters.id' => nil)
.with
.recursive(cte.to_arel)
.from(cte_alias)
diff --git a/app/models/clusters/concerns/application_status.rb b/app/models/clusters/concerns/application_status.rb
index 95ac95448dd..7485ee079ce 100644
--- a/app/models/clusters/concerns/application_status.rb
+++ b/app/models/clusters/concerns/application_status.rb
@@ -9,6 +9,7 @@ module Clusters
scope :available, -> do
where(
status: [
+ self.state_machines[:status].states[:externally_installed].value,
self.state_machines[:status].states[:installed].value,
self.state_machines[:status].states[:updated].value
]
@@ -28,6 +29,7 @@ module Clusters
state :uninstalling, value: 7
state :uninstall_errored, value: 8
state :uninstalled, value: 10
+ state :externally_installed, value: 11
# Used for applications that are pre-installed by the cluster,
# e.g. Knative in GCP Cloud Run enabled clusters
@@ -37,7 +39,7 @@ module Clusters
state :pre_installed, value: 9
event :make_externally_installed do
- transition any => :installed
+ transition any => :externally_installed
end
event :make_externally_uninstalled do
@@ -79,7 +81,7 @@ module Clusters
transition [:scheduled] => :uninstalling
end
- before_transition any => [:scheduled, :installed, :uninstalled] do |application, _|
+ before_transition any => [:scheduled, :installed, :uninstalled, :externally_installed] do |application, _|
application.status_reason = nil
end
@@ -114,7 +116,7 @@ module Clusters
end
def available?
- pre_installed? || installed? || updated?
+ pre_installed? || installed? || externally_installed? || updated?
end
def update_in_progress?
diff --git a/app/models/clusters/concerns/application_version.rb b/app/models/clusters/concerns/application_version.rb
index 6c0b014662c..dab0bd23e2e 100644
--- a/app/models/clusters/concerns/application_version.rb
+++ b/app/models/clusters/concerns/application_version.rb
@@ -5,11 +5,17 @@ module Clusters
module ApplicationVersion
extend ActiveSupport::Concern
+ EXTERNAL_VERSION = 'EXTERNALLY_INSTALLED'
+
included do
state_machine :status do
before_transition any => [:installed, :updated] do |application|
application.version = application.class.const_get(:VERSION, false)
end
+
+ before_transition any => [:externally_installed] do |application|
+ application.version = EXTERNAL_VERSION
+ end
end
end
diff --git a/app/models/clusters/concerns/prometheus_client.rb b/app/models/clusters/concerns/prometheus_client.rb
new file mode 100644
index 00000000000..10cb307addd
--- /dev/null
+++ b/app/models/clusters/concerns/prometheus_client.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Concerns
+ module PrometheusClient
+ extend ActiveSupport::Concern
+
+ included do
+ include PrometheusAdapter
+
+ def service_name
+ 'prometheus-prometheus-server'
+ end
+
+ def service_port
+ 80
+ end
+
+ def prometheus_client
+ return unless kube_client
+
+ proxy_url = kube_client.proxy_url('service', service_name, service_port, Gitlab::Kubernetes::Helm::NAMESPACE)
+
+ # ensures headers containing auth data are appended to original k8s client options
+ options = kube_client.rest_client.options
+ .merge(prometheus_client_default_options)
+ .merge(headers: kube_client.headers)
+ Gitlab::PrometheusClient.new(proxy_url, options)
+ rescue Kubeclient::HttpError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ENETUNREACH
+ # If users have mistakenly set parameters or removed the depended clusters,
+ # `proxy_url` could raise an exception because gitlab can not communicate with the cluster.
+ # Since `PrometheusAdapter#can_query?` is eargely loaded on environement pages in gitlab,
+ # we need to silence the exceptions
+ end
+
+ def configured?
+ kube_client.present? && available?
+ rescue Gitlab::UrlBlocker::BlockedUrlError
+ false
+ end
+
+ private
+
+ def kube_client
+ cluster&.kubeclient&.core_client
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/clusters/integrations/prometheus.rb b/app/models/clusters/integrations/prometheus.rb
new file mode 100644
index 00000000000..1496d8ff1dd
--- /dev/null
+++ b/app/models/clusters/integrations/prometheus.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Integrations
+ class Prometheus < ApplicationRecord
+ include ::Clusters::Concerns::PrometheusClient
+
+ self.table_name = 'clusters_integration_prometheus'
+ self.primary_key = :cluster_id
+
+ belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id
+
+ validates :cluster, presence: true
+ validates :enabled, inclusion: { in: [true, false] }
+
+ def available?
+ enabled?
+ end
+ end
+ end
+end