Class: Clusters::Cluster

Inherits:
ApplicationRecord show all
Includes:
AfterCommitQueue, FromUnion, Gitlab::Utils::StrongMemoize, HasEnvironmentScope, Presentable, ReactiveCaching
Defined in:
app/models/clusters/cluster.rb

Constant Summary collapse

APPLICATIONS =
{
  Clusters::Applications::Helm.application_name => Clusters::Applications::Helm,
  Clusters::Applications::Ingress.application_name => Clusters::Applications::Ingress,
  Clusters::Applications::CertManager.application_name => Clusters::Applications::CertManager,
  Clusters::Applications::Crossplane.application_name => Clusters::Applications::Crossplane,
  Clusters::Applications::Prometheus.application_name => Clusters::Applications::Prometheus,
  Clusters::Applications::Runner.application_name => Clusters::Applications::Runner,
  Clusters::Applications::Jupyter.application_name => Clusters::Applications::Jupyter,
  Clusters::Applications::Knative.application_name => Clusters::Applications::Knative,
  Clusters::Applications::ElasticStack.application_name => Clusters::Applications::ElasticStack,
  Clusters::Applications::Cilium.application_name => Clusters::Applications::Cilium
}.freeze
DEFAULT_ENVIRONMENT =
'*'
KUBE_INGRESS_BASE_DOMAIN =
'KUBE_INGRESS_BASE_DOMAIN'
APPLICATIONS_ASSOCIATIONS =
APPLICATIONS.values.map(&:association_name).freeze

Constants included from ReactiveCaching

ReactiveCaching::ExceededReactiveCacheLimit, ReactiveCaching::InvalidateReactiveCache, ReactiveCaching::WORK_TYPE

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from Presentable

#present

Methods included from HasEnvironmentScope

#environment_scope=

Methods inherited from ApplicationRecord

cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from SensitiveSerializableHash

#serializable_hash

Class Method Details

.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc) ⇒ Object


157
158
159
160
161
162
163
164
# File 'app/models/clusters/cluster.rb', line 157

def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc)
  return [] if clusterable.is_a?(Instance)

  hierarchy_groups = clusterable.ancestors_upto(hierarchy_order: hierarchy_order).eager_load(:clusters)
  hierarchy_groups = hierarchy_groups.merge(current_scope) if current_scope

  hierarchy_groups.flat_map(&:clusters) + Instance.new.clusters
end

.has_one_cluster_application(name) ⇒ Object

rubocop:disable Naming/PredicateName


56
57
58
59
# File 'app/models/clusters/cluster.rb', line 56

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
end

Instance Method Details

#all_projectsObject


203
204
205
206
207
208
# File 'app/models/clusters/cluster.rb', line 203

def all_projects
  return projects if project_type?
  return groups_projects if group_type?

  ::Project.all
end

#allow_user_defined_namespace?Boolean

Returns:

  • (Boolean)

335
336
337
# File 'app/models/clusters/cluster.rb', line 335

def allow_user_defined_namespace?
  project_type? || !managed?
end

#applicationsObject


257
258
259
260
261
# File 'app/models/clusters/cluster.rb', line 257

def applications
  APPLICATIONS.each_value.map do |application_class|
    find_or_build_application(application_class)
  end
end

#calculate_reactive_cacheObject


247
248
249
250
251
# File 'app/models/clusters/cluster.rb', line 247

def calculate_reactive_cache
  return unless enabled?

  connection_data.merge(Gitlab::Kubernetes::Node.new(self).all)
end

#clusterableObject


355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'app/models/clusters/cluster.rb', line 355

def clusterable
  return unless cluster_type

  case cluster_type
  when 'project_type'
    project
  when 'group_type'
    group
  when 'instance_type'
    instance
  else
    raise NotImplementedError
  end
end

#connection_errorObject


217
218
219
220
221
# File 'app/models/clusters/cluster.rb', line 217

def connection_error
  with_reactive_cache do |data|
    data[:connection_error]
  end
end

#connection_statusObject


235
236
237
238
239
# File 'app/models/clusters/cluster.rb', line 235

def connection_status
  with_reactive_cache do |data|
    data[:connection_status]
  end
end

#delete_cached_resources!Object


351
352
353
# File 'app/models/clusters/cluster.rb', line 351

def delete_cached_resources!
  kubernetes_namespaces.delete_all(:delete_all)
end

#elastic_stack_adapterObject


313
314
315
# File 'app/models/clusters/cluster.rb', line 313

def elastic_stack_adapter
  integration_elastic_stack
end

#elastic_stack_available?Boolean

Returns:

  • (Boolean)

321
322
323
# File 'app/models/clusters/cluster.rb', line 321

def elastic_stack_available?
  !!integration_elastic_stack_available?
end

#elasticsearch_clientObject


317
318
319
# File 'app/models/clusters/cluster.rb', line 317

def elasticsearch_client
  elastic_stack_adapter&.elasticsearch_client
end

#find_or_build_application(application_class) ⇒ Object

Raises:

  • (ArgumentError)

263
264
265
266
267
268
269
# File 'app/models/clusters/cluster.rb', line 263

def find_or_build_application(application_class)
  raise ArgumentError, "#{application_class} is not in APPLICATIONS" unless APPLICATIONS.value?(application_class)

  association_name = application_class.association_name

  public_send(association_name) || public_send("build_#{association_name}") # rubocop:disable GitlabSecurity/PublicSend
end

#find_or_build_integration_elastic_stackObject


275
276
277
# File 'app/models/clusters/cluster.rb', line 275

def find_or_build_integration_elastic_stack
  integration_elastic_stack || build_integration_elastic_stack
end

#find_or_build_integration_prometheusObject


271
272
273
# File 'app/models/clusters/cluster.rb', line 271

def find_or_build_integration_prometheus
  integration_prometheus || build_integration_prometheus
end

#first_groupObject Also known as: group


298
299
300
301
302
# File 'app/models/clusters/cluster.rb', line 298

def first_group
  strong_memoize(:first_group) do
    groups.first
  end
end

#first_projectObject Also known as: project


291
292
293
294
295
# File 'app/models/clusters/cluster.rb', line 291

def first_project
  strong_memoize(:first_project) do
    projects.first
  end
end

#instanceObject


305
306
307
# File 'app/models/clusters/cluster.rb', line 305

def instance
  Instance.new if instance_type?
end

#kube_ingress_domainObject


339
340
341
# File 'app/models/clusters/cluster.rb', line 339

def kube_ingress_domain
  @kube_ingress_domain ||= domain.presence || instance_domain
end

#kubeclientObject


309
310
311
# File 'app/models/clusters/cluster.rb', line 309

def kubeclient
  platform_kubernetes&.kubeclient if kubernetes?
end

#kubernetes_namespace_for(environment, deployable: environment.last_deployable) ⇒ Object


325
326
327
328
329
330
331
332
333
# File 'app/models/clusters/cluster.rb', line 325

def kubernetes_namespace_for(environment, deployable: environment.last_deployable)
  if deployable && environment.project_id != deployable.project_id
    raise ArgumentError, 'environment.project_id must match deployable.project_id'
  end

  managed_namespace(environment) ||
    ci_configured_namespace(deployable) ||
    default_namespace(environment)
end

#metrics_connection_errorObject


229
230
231
232
233
# File 'app/models/clusters/cluster.rb', line 229

def metrics_connection_error
  with_reactive_cache do |data|
    data[:metrics_connection_error]
  end
end

#node_connection_errorObject


223
224
225
226
227
# File 'app/models/clusters/cluster.rb', line 223

def node_connection_error
  with_reactive_cache do |data|
    data[:node_connection_error]
  end
end

#nodesObject


241
242
243
244
245
# File 'app/models/clusters/cluster.rb', line 241

def nodes
  with_reactive_cache do |data|
    data[:nodes]
  end
end

#persisted_applicationsObject


253
254
255
# File 'app/models/clusters/cluster.rb', line 253

def persisted_applications
  APPLICATIONS_ASSOCIATIONS.map(&method(:public_send)).compact
end

#platformObject


287
288
289
# File 'app/models/clusters/cluster.rb', line 287

def platform
  return platform_kubernetes if kubernetes?
end

#predefined_variablesObject


343
344
345
346
347
348
349
# File 'app/models/clusters/cluster.rb', line 343

def predefined_variables
  Gitlab::Ci::Variables::Collection.new.tap do |variables|
    break variables unless kube_ingress_domain

    variables.append(key: KUBE_INGRESS_BASE_DOMAIN, value: kube_ingress_domain)
  end
end

#prometheus_adapterObject


376
377
378
# File 'app/models/clusters/cluster.rb', line 376

def prometheus_adapter
  integration_prometheus
end

#providerObject


279
280
281
282
283
284
285
# File 'app/models/clusters/cluster.rb', line 279

def provider
  if gcp?
    provider_gcp
  elsif aws?
    provider_aws
  end
end

#serverless_domainObject


370
371
372
373
374
# File 'app/models/clusters/cluster.rb', line 370

def serverless_domain
  strong_memoize(:serverless_domain) do
    self.application_knative&.serverless_domain_cluster
  end
end

#status_nameObject


210
211
212
213
214
215
# File 'app/models/clusters/cluster.rb', line 210

def status_name
  return cleanup_status_name if cleanup_errored?
  return :cleanup_ongoing unless cleanup_not_started?

  provider&.status_name || connection_status.presence || :created
end