Read about our upcoming Code of Conduct on this issue

Commit a20d0823 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 903efabd2014
......@@ -7,7 +7,7 @@ class Admin::ServicesController < Admin::ApplicationController
before_action :service, only: [:edit, :update]
def index
@services = instance_level_services
@services = services_templates
end
def edit
......@@ -19,7 +19,7 @@ def edit
def update
if service.update(service_params[:service])
PropagateInstanceLevelServiceWorker.perform_async(service.id) if service.active?
PropagateServiceTemplateWorker.perform_async(service.id) if service.active?
redirect_to admin_application_settings_services_path,
notice: 'Application settings saved successfully'
......@@ -31,17 +31,17 @@ def update
private
# rubocop: disable CodeReuse/ActiveRecord
def instance_level_services
def services_templates
Service.available_services_names.map do |service_name|
service = "#{service_name}_service".camelize.constantize
service.where(instance: true).first_or_create
service_template = "#{service_name}_service".camelize.constantize
service_template.where(template: true).first_or_create
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def service
@service ||= Service.where(id: params[:id], instance: true).first
@service ||= Service.where(id: params[:id], template: true).first
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -8,11 +8,15 @@ class FunctionsController < Projects::ApplicationController
def index
respond_to do |format|
format.json do
functions = finder.execute
functions = finder.execute.select do |function|
can?(@current_user, :read_cluster, function.cluster)
end
serialized_functions = serialize_function(functions)
render json: {
knative_installed: finder.knative_installed,
functions: serialize_function(functions)
functions: serialized_functions
}.to_json
end
......@@ -23,11 +27,14 @@ def index
end
def show
@service = serialize_function(finder.service(params[:environment_id], params[:id]))
@prometheus = finder.has_prometheus?(params[:environment_id])
function = finder.service(params[:environment_id], params[:id])
return not_found unless function && can?(@current_user, :read_cluster, function.cluster)
@service = serialize_function(function)
return not_found if @service.nil?
@prometheus = finder.has_prometheus?(params[:environment_id])
respond_to do |format|
format.json do
render json: @service
......
......@@ -93,24 +93,32 @@ def knative_service(environment_scope, name)
.services
.select { |svc| svc["metadata"]["name"] == name }
add_metadata(finder, services).first unless services.nil?
attributes = add_metadata(finder, services).first
next unless attributes
Gitlab::Serverless::Service.new(attributes)
end
end
def knative_services
services_finders.map do |finder|
services = finder.services
attributes = add_metadata(finder, finder.services)
add_metadata(finder, services) unless services.nil?
attributes&.map do |attributes|
Gitlab::Serverless::Service.new(attributes)
end
end
end
def add_metadata(finder, services)
return if services.nil?
add_pod_count = services.one?
services.each do |s|
s["environment_scope"] = finder.cluster.environment_scope
s["cluster_id"] = finder.cluster.id
s["environment"] = finder.environment
s["cluster"] = finder.cluster
if add_pod_count
s["podcount"] = finder
......
......@@ -12,6 +12,10 @@ class BlobType < BaseObject
description: 'Blob highlighted data',
null: true
field :plain_highlighted_data, GraphQL::STRING_TYPE,
description: 'Blob plain highlighted data',
null: true
field :raw_path, GraphQL::STRING_TYPE,
description: 'Blob raw content endpoint path',
null: false
......
......@@ -290,6 +290,12 @@ def clusterable
end
end
def serverless_domain
strong_memoize(:serverless_domain) do
self.application_knative&.serverless_domain_cluster
end
end
private
def unique_management_project_environment_scope
......
......@@ -62,6 +62,8 @@ class PagesDomain < ApplicationRecord
scope :for_removal, -> { where("remove_at < ?", Time.now) }
scope :with_logging_info, -> { includes(project: [:namespace, :route]) }
def verified?
!!verified_at
end
......@@ -285,3 +287,5 @@ def certificate_should_be_present?
!auto_ssl_enabled? && project&.pages_https_only?
end
end
PagesDomain.prepend_if_ee('::EE::PagesDomain')
......@@ -1224,13 +1224,13 @@ def find_or_initialize_service(name)
service = find_service(services, name)
return service if service
# We should check if an instance-level service exists
instance_level_service = find_service(instance_level_services, name)
# We should check if template for the service exists
template = find_service(services_templates, name)
if instance_level_service
Service.build_from_instance(id, instance_level_service)
if template
Service.build_from_template(id, template)
else
# If no instance-level service exists, we should create a new service. Ex `build_gitlab_ci_service`
# If no template, we should create an instance. Ex `build_gitlab_ci_service`
public_send("build_#{name}_service") # rubocop:disable GitlabSecurity/PublicSend
end
end
......@@ -2460,8 +2460,8 @@ def fetch_branch_allows_collaboration(user, branch_name = nil)
end
end
def instance_level_services
@instance_level_services ||= Service.where(instance: true)
def services_templates
@services_templates ||= Service.where(template: true)
end
def ensure_pages_metadatum
......
......@@ -164,7 +164,7 @@ def issues_tracker
end
def one_issue_tracker
return if instance?
return if template?
return if project.blank?
if project.services.external_issue_trackers.where.not(id: id).any?
......
......@@ -85,7 +85,7 @@ def prometheus_client
end
def prometheus_available?
return false if instance?
return false if template?
return false unless project
project.all_clusters.enabled.any? { |cluster| cluster.application_prometheus_available? }
......
......@@ -32,7 +32,7 @@ class Service < ApplicationRecord
belongs_to :project, inverse_of: :services
has_one :service_hook
validates :project_id, presence: true, unless: proc { |service| service.instance? }
validates :project_id, presence: true, unless: proc { |service| service.template? }
validates :type, presence: true
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
......@@ -70,8 +70,8 @@ def editable?
true
end
def instance?
instance
def template?
template
end
def category
......@@ -299,15 +299,15 @@ def self.available_services_names
service_names.sort_by(&:downcase)
end
def self.build_from_instance(project_id, instance_level_service)
service = instance_level_service.dup
def self.build_from_template(project_id, template)
service = template.dup
if instance_level_service.supports_data_fields?
data_fields = instance_level_service.data_fields.dup
if template.supports_data_fields?
data_fields = template.data_fields.dup
data_fields.service = service
end
service.instance = false
service.template = false
service.project_id = project_id
service.active = false if service.active? && !service.valid?
service
......@@ -321,6 +321,10 @@ def deprecation_message
nil
end
def self.find_by_template
find_by(template: true)
end
# override if needed
def supports_data_fields?
false
......
......@@ -4,11 +4,13 @@ class SnippetBlobPresenter < BlobPresenter
def highlighted_data
return if blob.binary?
if blob.rich_viewer&.partial_name == 'markup'
blob.rendered_markup
else
highlight
end
highlight(plain: false)
end
def plain_highlighted_data
return if blob.binary?
highlight(plain: true)
end
def raw_path
......
......@@ -5,91 +5,31 @@ module Serverless
class ServiceEntity < Grape::Entity
include RequestAwareEntity
expose :name do |service|
service.dig('metadata', 'name')
end
expose :namespace do |service|
service.dig('metadata', 'namespace')
end
expose :environment_scope do |service|
service.dig('environment_scope')
end
expose :cluster_id do |service|
service.dig('cluster_id')
end
expose :name
expose :namespace
expose :environment_scope
expose :podcount
expose :created_at
expose :image
expose :description
expose :url
expose :detail_url do |service|
project_serverless_path(
request.project,
service.dig('environment_scope'),
service.dig('metadata', 'name'))
end
expose :podcount do |service|
service.dig('podcount')
service.environment_scope,
service.name)
end
expose :metrics_url do |service|
project_serverless_metrics_path(
request.project,
service.dig('environment_scope'),
service.dig('metadata', 'name')) + ".json"
end
expose :created_at do |service|
service.dig('metadata', 'creationTimestamp')
end
expose :url do |service|
knative_06_07_url(service) || knative_05_url(service)
end
expose :description do |service|
knative_07_description(service) || knative_05_06_description(service)
service.environment_scope,
service.name, format: :json)
end
expose :image do |service|
service.dig(
'spec',
'runLatest',
'configuration',
'build',
'template',
'name')
end
private
def knative_07_description(service)
service.dig(
'spec',
'template',
'metadata',
'annotations',
'Description'
)
end
def knative_05_url(service)
"http://#{service.dig('status', 'domain')}"
end
def knative_06_07_url(service)
service.dig('status', 'url')
end
def knative_05_06_description(service)
service.dig(
'spec',
'runLatest',
'configuration',
'revisionTemplate',
'metadata',
'annotations',
'Description')
expose :cluster_id do |service|
service.cluster&.id
end
end
end
......
......@@ -135,7 +135,7 @@ def save_project_and_import_data
if @project.save
unless @project.gitlab_project_import?
create_services_from_active_instance_level_services(@project)
create_services_from_active_templates(@project)
@project.create_labels
end
......@@ -161,9 +161,9 @@ def fail(error:)
end
# rubocop: disable CodeReuse/ActiveRecord
def create_services_from_active_instance_level_services(project)
Service.where(instance: true, active: true).each do |template|
service = Service.build_from_instance(project.id, template)
def create_services_from_active_templates(project)
Service.where(template: true, active: true).each do |template|
service = Service.build_from_template(project.id, template)
service.save!
end
end
......
# frozen_string_literal: true
module Projects
class PropagateInstanceLevelService
class PropagateServiceTemplate
BATCH_SIZE = 100
def self.propagate(*args)
new(*args).propagate
end
def initialize(instance_level_service)
@instance_level_service = instance_level_service
def initialize(template)
@template = template
end
def propagate
return unless @instance_level_service.active?
return unless @template.active?
Rails.logger.info("Propagating services for instance_level_service #{@instance_level_service.id}") # rubocop:disable Gitlab/RailsLogger
Rails.logger.info("Propagating services for template #{@template.id}") # rubocop:disable Gitlab/RailsLogger
propagate_projects_with_instance_level_service
propagate_projects_with_template
end
private
def propagate_projects_with_instance_level_service
def propagate_projects_with_template
loop do
batch = Project.uncached { project_ids_batch }
bulk_create_from_instance_level_service(batch) unless batch.empty?
bulk_create_from_template(batch) unless batch.empty?
break if batch.size < BATCH_SIZE
end
end
def bulk_create_from_instance_level_service(batch)
def bulk_create_from_template(batch)
service_list = batch.map do |project_id|
service_hash.values << project_id
end
......@@ -52,7 +52,7 @@ def project_ids_batch
SELECT true
FROM services
WHERE services.project_id = projects.id
AND services.type = '#{@instance_level_service.type}'
AND services.type = '#{@template.type}'
)
AND projects.pending_delete = false
AND projects.archived = false
......@@ -73,9 +73,9 @@ def bulk_insert_services(columns, values_array)
def service_hash
@service_hash ||=
begin
instance_hash = @instance_level_service.as_json(methods: :type).except('id', 'instance', 'project_id')
template_hash = @template.as_json(methods: :type).except('id', 'template', 'project_id')
instance_hash.each_with_object({}) do |(key, value), service_hash|
template_hash.each_with_object({}) do |(key, value), service_hash|
value = value.is_a?(Hash) ? value.to_json : value
service_hash[ActiveRecord::Base.connection.quote_column_name(key)] =
......@@ -97,11 +97,11 @@ def run_callbacks(batch)
# rubocop: enable CodeReuse/ActiveRecord
def active_external_issue_tracker?
@instance_level_service.issue_tracker? && !@instance_level_service.default
@template.issue_tracker? && !@template.default
end
def active_external_wiki?
@instance_level_service.type == 'ExternalWikiService'
@template.type == 'ExternalWikiService'
end
end
end
......@@ -10,8 +10,8 @@
%p.inline
= s_("MattermostService|See list of available commands in Mattermost after setting up this service, by entering")
%kbd.inline /&lt;trigger&gt; help
- unless enabled || @service.instance?
- unless enabled || @service.template?
= render 'projects/services/mattermost_slash_commands/detailed_help', subject: @service
- if enabled && !@service.instance?
- if enabled && !@service.template?
= render 'projects/services/mattermost_slash_commands/installation_info', subject: @service
......@@ -11,7 +11,7 @@
%p.inline
= s_("SlackService|See list of available commands in Slack after setting up this service, by entering")
%kbd.inline /&lt;command&gt; help
- unless @service.instance?
- unless @service.template?
%p= _("To set up this service:")
%ul.list-unstyled.indent-list
%li
......
......@@ -969,7 +969,7 @@
:latency_sensitive:
:resource_boundary: :unknown
:weight: 1
- :name: propagate_instance_level_service
- :name: propagate_service_template
:feature_category: :source_code_management
:has_external_dependencies:
:latency_sensitive:
......
......@@ -2,14 +2,14 @@
class PagesDomainRemovalCronWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
include CronjobQueue
feature_category :pages
worker_resource_boundary :cpu
def perform
PagesDomain.for_removal.find_each do |domain|
domain.destroy!
PagesDomain.for_removal.with_logging_info.find_each do |domain|
with_context(project: domain.project) { domain.destroy! }
rescue => e
Gitlab::ErrorTracking.track_exception(e)
end
......
......@@ -2,15 +2,17 @@
class PagesDomainSslRenewalCronWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
include CronjobQueue
feature_category :pages
def perform
return unless ::Gitlab::LetsEncrypt.enabled?
PagesDomain.need_auto_ssl_renewal.find_each do |domain|
PagesDomainSslRenewalWorker.perform_async(domain.id)
PagesDomain.need_auto_ssl_renewal.with_logging_info.find_each do |domain|
with_context(project: domain.project) do
PagesDomainSslRenewalWorker.perform_async(domain.id)
end
end
end
end
......@@ -2,15 +2,17 @@
class PagesDomainVerificationCronWorker
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
include CronjobQueue
feature_category :pages
def perform
return if Gitlab::Database.read_only?
PagesDomain.needs_verification.find_each do |domain|
PagesDomainVerificationWorker.perform_async(domain.id)
PagesDomain.needs_verification.with_logging_info.find_each do |domain|
with_context(project: domain.project) do
PagesDomainVerificationWorker.perform_async(domain.id)
end
end
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment