Commit 48d8bdca authored by Kamil Trzcinski's avatar Kamil Trzcinski

Abstract EE code from CE codebase

parent fb08198b
......@@ -4,6 +4,6 @@ class Groups::PipelineQuotaController < Groups::ApplicationController
layout 'group_settings'
def index
@projects = @group.projects.with_shared_runners.page(params[:page])
@projects = @group.projects.with_shared_runners_limit_enabled.page(params[:page])
end
end
class ApplicationSetting < ActiveRecord::Base
include CacheMarkdownField
include TokenAuthenticatable
prepend EE::ApplicationSetting
add_authentication_token_field :runners_registration_token
add_authentication_token_field :health_check_access_token
......@@ -123,9 +124,6 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { only_integer: true, greater_than: :housekeeping_full_repack_period }
validates :shared_runners_minutes,
numericality: { greater_than_or_equal_to: 0 }
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
......
......@@ -2,7 +2,7 @@ module Ci
class Build < CommitStatus
include TokenAuthenticatable
include AfterCommitQueue
include EE::Build
prepend EE::Build
belongs_to :runner
belongs_to :trigger_request
......
......@@ -4,13 +4,13 @@ module EE
# This module is intended to encapsulate EE-specific model logic
# and be included in the `Namespace` model
module Namespace
extend ActiveSupport::Concern
extend ActiveSupport::Prependable
included do
has_one :namespace_metrics, dependent: :destroy
prepended do
has_one :namespace_statistics, dependent: :destroy
delegate :shared_runners_minutes, :shared_runners_minutes_last_reset,
to: :namespace_metrics, allow_nil: true
to: :namespace_statistics, allow_nil: true
end
def actual_shared_runners_minutes_limit
......
......@@ -4,11 +4,13 @@ module EE
# This module is intended to encapsulate EE-specific model logic
# and be included in the `Project` model
module Project
extend ActiveSupport::Concern
extend ActiveSupport::Prependable
prepended do
scope :with_shared_runners_limit_enabled, -> { with_shared_runners.non_public_only }
included do
delegate :shared_runners_minutes, :shared_runners_minutes_last_reset,
to: :project_metrics, allow_nil: true
to: :project_statistics, allow_nil: true
delegate :actual_shared_runners_minutes_limit,
:shared_runners_minutes_used?, to: :namespace
......@@ -16,16 +18,12 @@ module EE
has_one :project_metrics, dependent: :destroy
end
def shared_runners_minutes_limit_enabled?
!public? && shared_runners_enabled? && namespace.shared_runners_minutes_limit_enabled?
def shared_runners_available?
super && !namespace.shared_runners_minutes_used?
end
def shared_runners
if shared_runners_enabled? && !namespace.shared_runners_minutes_used?
Ci::Runner.shared
else
Ci::Runner.none
end
def shared_runners_minutes_limit_enabled?
!public? && shared_runners_enabled? && namespace.shared_runners_minutes_limit_enabled?
end
end
end
class Namespace < ActiveRecord::Base
acts_as_paranoid
include EE::Namespace
prepend EE::Namespace
include CacheMarkdownField
include Sortable
include Gitlab::ShellAdapter
......
class NamespaceMetrics < ActiveRecord::Base
class NamespaceStatistics < ActiveRecord::Base
belongs_to :namespace
validates :namespace, presence: true
......
......@@ -18,7 +18,7 @@ class Project < ActiveRecord::Base
include SelectForProjectAuthorization
include Routable
prepend EE::GeoAwareAvatar
include EE::Project
prepend EE::Project
extend Gitlab::ConfigHelper
......@@ -246,7 +246,7 @@ class Project < ActiveRecord::Base
scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') }
scope :with_statistics, -> { includes(:statistics) }
scope :with_shared_runners_limit_enabled, -> { where(shared_runners_enabled: true).non_public_only }
scope :with_shared_runners, -> { where(shared_runners_enabled: true) }
# "enabled" here means "not disabled". It includes private features!
scope :with_feature_enabled, ->(feature) {
......@@ -1241,9 +1241,13 @@ class Project < ActiveRecord::Base
project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED)
end
def shared_runners_available?
shared_runners_enabled?
end
def shared_runners
shared_runners_enabled? ? Ci::Runner.shared : Ci::Runner.none
end unless defined?(:shared_runners)
shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none
end
def any_runners?(&block)
if runners.active.any?(&block)
......
......@@ -3,6 +3,7 @@ module Ci
# proper pending build to runner on runner API request
class RegisterBuildService
include Gitlab::CurrentSettings
prepend EE::Ci::RegisterBuildService
attr_reader :runner
......@@ -13,11 +14,7 @@ module Ci
def execute
builds =
if runner.shared?
if shared_runner_build_limits_feature_enabled?
builds_for_shared_runner_with_build_minutes_check
else
builds_for_shared_runner
end
builds_for_shared_runner
else
builds_for_specific_runner
end
......@@ -41,13 +38,6 @@ module Ci
private
def builds_for_shared_runner_with_build_minutes_check
# select projects which have allowed number of shared runner minutes or are public
builds_for_shared_runner.
where("projects.visibility_level=? OR (#{builds_check_limit.to_sql})=1",
Gitlab::VisibilityLevel::PUBLIC)
end
def builds_for_shared_runner
new_builds.
# don't run projects which have not enabled shared runners and builds
......@@ -62,20 +52,6 @@ module Ci
order('COALESCE(project_builds.running_builds, 0) ASC', 'ci_builds.id ASC')
end
def builds_check_limit
Namespace.reorder(nil).
where("namespaces.id = projects.namespace_id").
joins('LEFT JOIN namespace_metrics ON namespace_metrics.namespace_id = namespaces.id').
where('COALESCE(namespaces.shared_runners_minutes_limit, ?, 0) = 0 OR ' \
'COALESCE(namespace_metrics.shared_runners_minutes, 0) < COALESCE(namespaces.shared_runners_minutes_limit, ?, 0)',
application_shared_runners_minutes, application_shared_runners_minutes).
select('1')
end
def application_shared_runners_minutes
current_application_settings.shared_runners_minutes
end
def builds_for_specific_runner
new_builds.where(project: runner.projects.with_builds_enabled).order('created_at ASC')
end
......
module EE
module Ci
# This class responsible for assigning
# proper pending build to runner on runner API request
class RegisterBuildService
extend ActiveSupport::Prependable
def builds_for_shared_runner
return super unless shared_runner_build_limits_feature_enabled?
# select projects which have allowed number of shared runner minutes or are public
super.
where("projects.visibility_level=? OR (#{builds_check_limit.to_sql})=1",
Gitlab::VisibilityLevel::PUBLIC)
end
def builds_check_limit
Namespace.reorder(nil).
where('namespaces.id = projects.namespace_id').
joins('LEFT JOIN namespace_statistics ON namespace_statistics.namespace_id = namespaces.id').
where('COALESCE(namespaces.shared_runners_minutes_limit, ?, 0) = 0 OR ' \
'COALESCE(namespace_statistics.shared_runners_minutes, 0) < COALESCE(namespaces.shared_runners_minutes_limit, ?, 0)',
application_shared_runners_minutes, application_shared_runners_minutes).
select('1')
end
def application_shared_runners_minutes
current_application_settings.shared_runners_minutes
end
def shared_runner_build_limits_feature_enabled?
ENV['DISABLE_SHARED_RUNNER_BUILD_MINUTES_LIMIT'].to_s != 'true'
end
end
end
end
......@@ -4,21 +4,21 @@ class UpdateBuildMinutesService < BaseService
return unless build.complete?
return unless build.duration
ProjectMetrics.update_counters(project_metrics,
ProjectStatistics.update_counters(project.statistics,
shared_runners_minutes: build.duration)
NamespaceMetrics.update_counters(namespace_metrics,
shared_runners_minutes: build.duration)
NamespaceStatistics.update_counters(namespace_statistics,
shared_runners_minutes: build.duration)
end
private
def namespace_metrics
namespace.namespace_metrics || namespace.create_namespace_metrics
def namespace_statistics
namespace.namespace_statistics || namespace.create_namespace_statistics
end
def project_metrics
project.project_metrics || project.create_project_metrics
def project_statistics
project.statistics || project.create_statistics(namespace: namespace)
end
def namespace
......
......@@ -11,7 +11,7 @@ class ClearSharedRunnersMinutesWorker
shared_runners_minutes: 0,
shared_runners_minutes_last_reset: Time.now)
NamespaceMetrics.update_all(
NamespaceStatistics.update_all(
shared_runners_minutes: 0,
shared_runners_minutes_last_reset: Time.now)
end
......
class CreateTableNamespaceMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :namespace_metrics do |t|
t.integer :namespace_id, null: false
t.integer :shared_runners_minutes, default: 0, null: false
t.timestamp :shared_runners_minutes_last_reset
end
add_foreign_key :namespace_metrics, :namespaces, on_delete: :cascade
end
end
class CreateTableProjectMetrics < ActiveRecord::Migration
class CreateTableNamespaceStatistics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :project_metrics do |t|
t.integer :project_id, null: false
create_table :namespace_statistics do |t|
t.references :namespace, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
t.integer :shared_runners_minutes, default: 0, null: false
t.timestamp :shared_runners_minutes_last_reset
end
add_foreign_key :project_metrics, :projects, on_delete: :cascade
end
end
class AddSharedRunnersMinutesToProjectStatistics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
counter_column = { limit: 8, null: false, default: 0 }
add_column :project_statistics, :shared_runners_minutes, :integer, counter_column
add_column :project_statistics, :shared_runners_minutes_last_reset, :timestamp
end
end
class AddIndexToNamespaceMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def change
add_concurrent_index :namespace_metrics, [:namespace_id], { unique: true }
end
end
class AddIndexToProjectMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def change
add_concurrent_index :project_metrics, [:project_id], { unique: true }
end
end
......@@ -825,13 +825,13 @@ ActiveRecord::Schema.define(version: 20170106172224) do
add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree
add_index "milestones", ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
create_table "namespace_metrics", force: :cascade do |t|
create_table "namespace_statistics", force: :cascade do |t|
t.integer "namespace_id", null: false
t.integer "shared_runners_minutes", default: 0, null: false
t.datetime "shared_runners_minutes_last_reset"
end
add_index "namespace_metrics", ["namespace_id"], name: "index_namespace_metrics_on_namespace_id", unique: true, using: :btree
add_index "namespace_statistics", ["namespace_id"], name: "index_namespace_metrics_on_namespace_id", unique: true, using: :btree
create_table "namespaces", force: :cascade do |t|
t.string "name", null: false
......@@ -1515,7 +1515,7 @@ ActiveRecord::Schema.define(version: 20170106172224) do
add_foreign_key "merge_request_metrics", "merge_requests", on_delete: :cascade
add_foreign_key "merge_requests_closing_issues", "issues", on_delete: :cascade
add_foreign_key "merge_requests_closing_issues", "merge_requests", on_delete: :cascade
add_foreign_key "namespace_metrics", "namespaces", on_delete: :cascade
add_foreign_key "namespace_statistics", "namespaces", on_delete: :cascade
add_foreign_key "path_locks", "projects"
add_foreign_key "path_locks", "users"
add_foreign_key "personal_access_tokens", "users"
......
# This module is based on: https://gist.github.com/bcardarella/5735987
module ActiveSupport
module Prependable
include ActiveSupport::Concern
def self.extended(base) #:nodoc:
base.instance_variable_set(:@_dependencies, [])
end
def prepend_features(base)
if base.instance_variable_defined?(:@_dependencies)
base.instance_variable_get(:@_dependencies) << self
return false
else
return false if base < self
super
base.singleton_class.send(:prepend, const_get('ClassMethods')) if const_defined?(:ClassMethods)
@_dependencies.each { |dep| base.send(:include, dep) }
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
end
end
alias_method :prepended, :included
end
end
FactoryGirl.define do
factory :namespace_metrics do
factory :namespace_statistics do
namespace factory: :namespace
end
end
......@@ -5,7 +5,7 @@ FactoryGirl.define do
owner
trait :with_build_minutes do
namespace_metrics factory: :namespace_metrics, shared_runners_minutes: 400
namespace_statistics factory: :namespace_statistics, shared_runners_minutes: 400
end
trait :with_build_minutes_limit do
......@@ -13,12 +13,12 @@ FactoryGirl.define do
end
trait :with_not_used_build_minutes_limit do
namespace_metrics factory: :namespace_metrics, shared_runners_minutes: 300
namespace_statistics factory: :namespace_statistics, shared_runners_minutes: 300
shared_runners_minutes_limit 500
end
trait :with_used_build_minutes_limit do
namespace_metrics factory: :namespace_metrics, shared_runners_minutes: 1000
namespace_statistics factory: :namespace_statistics, shared_runners_minutes: 1000
shared_runners_minutes_limit 500
end
end
......
......@@ -3,10 +3,10 @@ require 'spec_helper'
describe Namespace, models: true do
let!(:namespace) { create(:namespace) }
it { is_expected.to have_one(:namespace_metrics).dependent(:destroy) }
it { is_expected.to have_one(:namespace_statistics).dependent(:destroy) }
it { is_expected.to delegate_method(:shared_runners_minutes).to(:namespace_metrics) }
it { is_expected.to delegate_method(:shared_runners_minutes_last_reset).to(:namespace_metrics) }
it { is_expected.to delegate_method(:shared_runners_minutes).to(:namespace_statistics) }
it { is_expected.to delegate_method(:shared_runners_minutes_last_reset).to(:namespace_statistics) }
describe '#shared_runners_enabled?' do
subject { namespace.shared_runners_enabled? }
......
require 'spec_helper'
describe NamespaceMetrics, models: true do
describe NamespaceStatistics, models: true do
it { is_expected.to belong_to(:namespace) }
it { is_expected.to validate_presence_of(:namespace) }
......
......@@ -22,7 +22,7 @@ describe UpdateBuildMinutesService, services: true do
expect(project.project_metrics.reload.shared_runners_minutes).
to eq(build.duration.to_i)
expect(namespace.namespace_metrics.reload.shared_runners_minutes).
expect(namespace.namespace_statistics.reload.shared_runners_minutes).
to eq(build.duration.to_i)
end
......@@ -38,7 +38,7 @@ describe UpdateBuildMinutesService, services: true do
expect(project.project_metrics.reload.shared_runners_minutes).
to eq(100 + build.duration.to_i)
expect(namespace.namespace_metrics.reload.shared_runners_minutes).
expect(namespace.namespace_statistics.reload.shared_runners_minutes).
to eq(100 + build.duration.to_i)
end
end
......@@ -51,7 +51,7 @@ describe UpdateBuildMinutesService, services: true do
subject
expect(project.project_metrics).to be_nil
expect(namespace.namespace_metrics).to be_nil
expect(namespace.namespace_statistics).to be_nil
end
end
end
......
......@@ -28,18 +28,18 @@ describe ClearSharedRunnersMinutesWorker do
end
context 'when project metrics are defined' do
let!(:namespace_metrics) { create(:namespace_metrics, shared_runners_minutes: 100) }
let!(:namespace_statistics) { create(:namespace_statistics, shared_runners_minutes: 100) }
it 'clears counters' do
subject
expect(namespace_metrics.reload.shared_runners_minutes).to be_zero
expect(namespace_statistics.reload.shared_runners_minutes).to be_zero
end
it 'resets timer' do
subject
expect(namespace_metrics.reload.shared_runners_minutes_last_reset).to be_like_time(Time.now)
expect(namespace_statistics.reload.shared_runners_minutes_last_reset).to be_like_time(Time.now)
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