Commit 1731bab7 authored by Nick Thomas's avatar Nick Thomas

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2017-06-07

parents 918210a8 40588ddd
...@@ -117,6 +117,14 @@ ...@@ -117,6 +117,14 @@
} }
} }
.user-settings-pipeline-quota {
margin-top: $gl-padding;
.pipeline-quota {
border-top: none;
}
}
table.pipeline-project-metrics tr td { table.pipeline-project-metrics tr td {
padding: $gl-padding; padding: $gl-padding;
} }
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
&.expanded { &.expanded {
max-height: none; max-height: none;
overflow-y: hidden; overflow-y: visible;
animation: expandMaxHeight 300ms ease-in; animation: expandMaxHeight 300ms ease-in;
} }
......
class Profiles::PipelineQuotaController < Profiles::ApplicationController
def index
@namespace = current_user.namespace
@projects = @namespace.projects.with_shared_runners_limit_enabled.page(params[:page])
end
end
module EE module EE
module GroupsHelper module NamespaceHelper
def group_shared_runner_limits_quota(group) def namespace_shared_runner_limits_quota(namespace)
used = group.shared_runners_minutes.to_i used = namespace.shared_runners_minutes.to_i
if group.shared_runners_minutes_limit_enabled? if namespace.shared_runners_minutes_limit_enabled?
limit = group.actual_shared_runners_minutes_limit limit = namespace.actual_shared_runners_minutes_limit
status = group.shared_runners_minutes_used? ? 'over_quota' : 'under_quota' status = namespace.shared_runners_minutes_used? ? 'over_quota' : 'under_quota'
else else
limit = 'Unlimited' limit = 'Unlimited'
status = 'disabled' status = 'disabled'
...@@ -16,14 +16,14 @@ module EE ...@@ -16,14 +16,14 @@ module EE
end end
end end
def group_shared_runner_limits_percent_used(group) def namespace_shared_runner_limits_percent_used(namespace)
return 0 unless group.shared_runners_minutes_limit_enabled? return 0 unless namespace.shared_runners_minutes_limit_enabled?
100 * group.shared_runners_minutes.to_i / group.actual_shared_runners_minutes_limit 100 * namespace.shared_runners_minutes.to_i / namespace.actual_shared_runners_minutes_limit
end end
def group_shared_runner_limits_progress_bar(group) def namespace_shared_runner_limits_progress_bar(namespace)
percent = [group_shared_runner_limits_percent_used(group), 100].min percent = [namespace_shared_runner_limits_percent_used(namespace), 100].min
status = status =
if percent == 100 if percent == 100
......
class Geo::BaseRegistry < ActiveRecord::Base class Geo::BaseRegistry < ActiveRecord::Base
self.abstract_class = true self.abstract_class = true
if Gitlab::Geo.configured? && (Gitlab::Geo.secondary? || Rails.env.test?) if Gitlab::Geo.secondary_role_enabled?
establish_connection Rails.configuration.geo_database establish_connection Rails.configuration.geo_database
end end
end end
...@@ -21,9 +21,7 @@ class GeoNode < ActiveRecord::Base ...@@ -21,9 +21,7 @@ class GeoNode < ActiveRecord::Base
validates :encrypted_secret_access_key, presence: true validates :encrypted_secret_access_key, presence: true
after_initialize :build_dependents after_initialize :build_dependents
after_save :refresh_bulk_notify_worker_status
after_save :expire_cache! after_save :expire_cache!
after_destroy :refresh_bulk_notify_worker_status
after_destroy :expire_cache! after_destroy :expire_cache!
before_validation :update_dependents_attributes before_validation :update_dependents_attributes
...@@ -130,10 +128,6 @@ class GeoNode < ActiveRecord::Base ...@@ -130,10 +128,6 @@ class GeoNode < ActiveRecord::Base
{ protocol: schema, host: host, port: port, script_name: relative_url } { protocol: schema, host: host, port: port, script_name: relative_url }
end end
def refresh_bulk_notify_worker_status
Gitlab::Geo.configure_cron_jobs!
end
def build_dependents def build_dependents
unless persisted? unless persisted?
self.build_geo_node_key if geo_node_key.nil? self.build_geo_node_key if geo_node_key.nil?
......
...@@ -41,6 +41,7 @@ module Issues ...@@ -41,6 +41,7 @@ module Issues
'Due Date' => -> (issue) { issue.due_date&.to_s(:csv) }, 'Due Date' => -> (issue) { issue.due_date&.to_s(:csv) },
'Created At (UTC)' => -> (issue) { issue.created_at&.to_s(:csv) }, 'Created At (UTC)' => -> (issue) { issue.created_at&.to_s(:csv) },
'Updated At (UTC)' => -> (issue) { issue.updated_at&.to_s(:csv) }, 'Updated At (UTC)' => -> (issue) { issue.updated_at&.to_s(:csv) },
'Closed At (UTC)' => -> (issue) { issue.closed_at&.to_s(:csv) },
'Milestone' => -> (issue) { issue.milestone&.title }, 'Milestone' => -> (issue) { issue.milestone&.title },
'Labels' => -> (issue) { @labels[issue.id].sort.join(',').presence } 'Labels' => -> (issue) { @labels[issue.id].sort.join(',').presence }
} }
......
...@@ -9,44 +9,5 @@ ...@@ -9,44 +9,5 @@
%strong= @group.name %strong= @group.name
group group
.pipeline-quota.container-fluid = render "namespaces/pipelines_quota/list",
.row locals: { namespace: @group, projects: @projects }
.col-sm-6
%strong
- last_reset = @group.shared_runners_seconds_last_reset
- if last_reset
Usage since
= last_reset.strftime('%b %d, %Y')
- else
Current period usage
%div
= group_shared_runner_limits_quota(@group)
minutes
.col-sm-6.right
- if @group.shared_runners_minutes_limit_enabled?
#{group_shared_runner_limits_percent_used(@group)}% used
- else
Unlimited
= group_shared_runner_limits_progress_bar(@group)
%table.table.pipeline-project-metrics
%thead
%tr
%th Project
%th Minutes
%tbody
- @projects.each do |project|
%tr
%td
.avatar-container.s20.hidden-xs
= project_icon(project, alt: '', class: 'avatar project-avatar s20')
%strong= link_to project.name, project
%td
= project.shared_runners_minutes
- if @projects.blank?
%tr
%td{ colspan: 2 }
.nothing-here-block This group has no projects which use shared runners
= paginate @projects, theme: "gitlab"
...@@ -51,3 +51,7 @@ ...@@ -51,3 +51,7 @@
= link_to audit_log_profile_path, title: 'Authentication log' do = link_to audit_log_profile_path, title: 'Authentication log' do
%span %span
Authentication log Authentication log
= nav_link(path: 'profiles#pipeline_quota') do
= link_to profile_pipeline_quota_path, title: 'Pipeline quota' do
%span
Pipeline quota
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
%li %li
%span.light Pipeline minutes quota: %span.light Pipeline minutes quota:
%strong %strong
= group_shared_runner_limits_quota(namespace) = namespace_shared_runner_limits_quota(namespace)
= link_to icon('question-circle'), help_page_path("user/admin_area/settings/continuous_integration", anchor: "shared-runners-build-minutes-quota"), target: '_blank' = link_to icon('question-circle'), help_page_path("user/admin_area/settings/continuous_integration", anchor: "shared-runners-build-minutes-quota"), target: '_blank'
- namespace = locals.fetch(:namespace)
- projects = locals.fetch(:projects)
.pipeline-quota.container-fluid
.row
.col-sm-6
%strong
- last_reset = namespace.shared_runners_seconds_last_reset
- if last_reset
Usage since
= last_reset.strftime('%b %d, %Y')
- else
Current period usage
%div
= namespace_shared_runner_limits_quota(namespace)
minutes
.col-sm-6.right
- if namespace.shared_runners_minutes_limit_enabled?
#{namespace_shared_runner_limits_percent_used(namespace)}% used
- else
Unlimited
= namespace_shared_runner_limits_progress_bar(namespace)
%table.table.pipeline-project-metrics
%thead
%tr
%th Project
%th Minutes
%tbody
- projects.each do |project|
%tr
%td
.avatar-container.s20.hidden-xs
= project_icon(project, alt: '', class: 'avatar project-avatar s20')
%strong= link_to project.name, project
%td
= project.shared_runners_minutes
- if projects.blank?
%tr
%td{ colspan: 2 }
.nothing-here-block This group has no projects which use shared runners
= paginate projects, theme: "gitlab"
- page_title 'Personal pipelines quota'
= render 'profiles/head'
.user-settings-pipeline-quota.row
.profile-settings-sidebar.col-lg-3
%h4
Personal pipelines quota
= link_to icon('question-circle'), help_page_path("user/admin_area/settings/continuous_integration", anchor: "shared-runners-build-minutes-quota"), target: '_blank'
%p.light
Monthly build minutes usage across shared Runners
.col-lg-9
= render "namespaces/pipelines_quota/list",
locals: { namespace: @namespace, projects: @projects }
.row - expanded = Rails.env.test?
= form_errors(@project) %section.settings.project-mirror-settings
.row.prepend-top-default.append-bottom-default .settings-header
= form_for @project, url: namespace_project_mirror_path(@project.namespace, @project) do |f| %h4
.col-lg-3
%h4.prepend-top-0
Pull from a remote repository Pull from a remote repository
%p.light %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand'
%p
Set up your project to automatically have its branches, tags, and commits Set up your project to automatically have its branches, tags, and commits
updated from an upstream repository every hour. updated from an upstream repository every hour.
= link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pulling-from-a-remote-repository'), target: '_blank' = link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pulling-from-a-remote-repository'), target: '_blank'
.col-lg-9 .settings-content.no-animate{ class: ('expanded' if expanded) }
%h5.prepend-top-0 = form_for @project, url: namespace_project_mirror_path(@project.namespace, @project) do |f|
%div
= form_errors(@project)
%h5
Set up mirror repository Set up mirror repository
= render "shared/mirror_update_button" = render "shared/mirror_update_button"
- if @project.mirror_last_update_failed? - if @project.mirror_last_update_failed?
...@@ -43,16 +46,22 @@ ...@@ -43,16 +46,22 @@
They need to have at least master access to this project. They need to have at least master access to this project.
- if @project.builds_enabled? - if @project.builds_enabled?
= render "shared/mirror_trigger_builds_setting", f: f = render "shared/mirror_trigger_builds_setting", f: f
.col-sm-12 = f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror'
%hr
.col-lg-3 %section.settings
%h4.prepend-top-0 .settings-header
%h4
Push to a remote repository Push to a remote repository
%p.light %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand'
%p
Set up the remote repository that you want to update with the content of the current repository Set up the remote repository that you want to update with the content of the current repository
every time someone pushes to it. every time someone pushes to it.
= link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pushing-to-a-remote-repository'), target: '_blank' = link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pushing-to-a-remote-repository'), target: '_blank'
.col-lg-9 .settings-content.no-animate{ class: ('expanded' if expanded) }
= form_for @project, url: namespace_project_mirror_path(@project.namespace, @project) do |f|
%div
= form_errors(@project)
= render "shared/remote_mirror_update_button", remote_mirror: @remote_mirror = render "shared/remote_mirror_update_button", remote_mirror: @remote_mirror
- if @remote_mirror.last_error.present? - if @remote_mirror.last_error.present?
.panel.panel-danger .panel.panel-danger
...@@ -76,4 +85,3 @@ ...@@ -76,4 +85,3 @@
= rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git' = rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git'
= render "projects/mirrors/instructions" = render "projects/mirrors/instructions"
= f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror' = f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror'
%hr
...@@ -2,14 +2,7 @@ ...@@ -2,14 +2,7 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('protected_tags') = page_specific_javascript_bundle_tag('protected_tags')
<<<<<<< HEAD %section.settings.js-protected-tags-container{ data: { "groups-autocomplete" => "#{autocomplete_project_groups_path(format: :json)}", "users-autocomplete" => "#{autocomplete_users_path(format: :json)}" } }
.row.prepend-top-default.append-bottom-default.js-protected-tags-container{ data: { "groups-autocomplete" => "#{autocomplete_project_groups_path(format: :json)}", "users-autocomplete" => "#{autocomplete_users_path(format: :json)}" } }
.col-lg-3
%h4.prepend-top-0
Protected Tags
%p.prepend-top-20
=======
%section.settings
.settings-header .settings-header
%h4 %h4
Protected Tags Protected Tags
...@@ -19,20 +12,14 @@ ...@@ -19,20 +12,14 @@
Limit access to creating and updating tags. Limit access to creating and updating tags.
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content.no-animate{ class: ('expanded' if expanded) }
%p %p
>>>>>>> ce/master
By default, protected tags are designed to: By default, protected tags are designed to:
%ul %ul
%li Prevent tag creation by everybody except Masters %li Prevent tag creation by everybody except Masters
%li Prevent <strong>anyone</strong> from updating the tag %li Prevent <strong>anyone</strong> from updating the tag
%li Prevent <strong>anyone</strong> from deleting the tag %li Prevent <strong>anyone</strong> from deleting the tag
<<<<<<< HEAD
%p.append-bottom-0 Read more about #{link_to "protected tags", help_page_path("user/project/protected_tags"), class: "underlined-link"}.
.col-lg-9
=======
%p Read more about #{link_to "protected tags", help_page_path("user/project/protected_tags"), class: "underlined-link"}. %p Read more about #{link_to "protected tags", help_page_path("user/project/protected_tags"), class: "underlined-link"}.
>>>>>>> ce/master
- if can? current_user, :admin_project, @project - if can? current_user, :admin_project, @project
= render 'projects/protected_tags/create_protected_tag' = render 'projects/protected_tags/create_protected_tag'
......
.row.prepend-top-default.append-bottom-default - expanded = Rails.env.test?
.col-lg-3 %section.settings
%h4.prepend-top-0 .settings-header
%h4
Push Rules Push Rules
%p.light %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand'
%p
Push Rules outline what is accepted for this project. Push Rules outline what is accepted for this project.
.col-lg-9 .settings-content.no-animate{ class: ('expanded' if expanded) }
%h5.prepend-top-0 %h5
Add new push rule Add new push rule
= form_for [@project.namespace.becomes(Namespace), @project, @push_rule] do |f| = form_for [@project.namespace.becomes(Namespace), @project, @push_rule] do |f|
= form_errors(@push_rule) = form_errors(@push_rule)
......
...@@ -22,7 +22,7 @@ class GeoFileDownloadDispatchWorker ...@@ -22,7 +22,7 @@ class GeoFileDownloadDispatchWorker
# files, excluding ones in progress. # files, excluding ones in progress.
# 5. Quit when we have scheduled all downloads or exceeded an hour. # 5. Quit when we have scheduled all downloads or exceeded an hour.
def perform def perform
return unless Gitlab::Geo.configured? return unless Gitlab::Geo.secondary_role_enabled?
return unless Gitlab::Geo.secondary? return unless Gitlab::Geo.secondary?
@start_time = Time.now @start_time = Time.now
...@@ -153,7 +153,7 @@ class GeoFileDownloadDispatchWorker ...@@ -153,7 +153,7 @@ class GeoFileDownloadDispatchWorker
def node_enabled? def node_enabled?
# Only check every minute to avoid polling the DB excessively # Only check every minute to avoid polling the DB excessively
unless @last_enabled_check.present? && (Time.now - @last_enabled_check > 1.minute) unless @last_enabled_check.present? && @last_enabled_check > 1.minute.ago
@last_enabled_check = Time.now @last_enabled_check = Time.now
@current_node_enabled = nil @current_node_enabled = nil
end end
......
...@@ -7,7 +7,7 @@ class GeoRepositorySyncWorker ...@@ -7,7 +7,7 @@ class GeoRepositorySyncWorker
LAST_SYNC_INTERVAL = 24.hours LAST_SYNC_INTERVAL = 24.hours
def perform def perform
return unless Gitlab::Geo.configured? return unless Gitlab::Geo.secondary_role_enabled?
return unless Gitlab::Geo.primary_node.present? return unless Gitlab::Geo.primary_node.present?
start_time = Time.now start_time = Time.now
...@@ -20,7 +20,7 @@ class GeoRepositorySyncWorker ...@@ -20,7 +20,7 @@ class GeoRepositorySyncWorker
project_ids.each do |project_id| project_ids.each do |project_id|
begin begin
break if over_time?(start_time) break if over_time?(start_time)
break unless Gitlab::Geo.current_node_enabled? break unless node_enabled?
# We try to obtain a lease here for the entire sync process because we # We try to obtain a lease here for the entire sync process because we
# want to sync the repositories continuously at a controlled rate # want to sync the repositories continuously at a controlled rate
...@@ -73,6 +73,16 @@ class GeoRepositorySyncWorker ...@@ -73,6 +73,16 @@ class GeoRepositorySyncWorker
Time.now - start_time >= RUN_TIME Time.now - start_time >= RUN_TIME
end end
def node_enabled?
# Only check every minute to avoid polling the DB excessively
unless @last_enabled_check.present? && @last_enabled_check > 1.minute.ago
@last_enabled_check = Time.now
@current_node_enabled = nil
end
@current_node_enabled ||= Gitlab::Geo.current_node_enabled?
end
def try_obtain_lease def try_obtain_lease
lease = Gitlab::ExclusiveLease.new(lease_key, timeout: lease_timeout).try_obtain lease = Gitlab::ExclusiveLease.new(lease_key, timeout: lease_timeout).try_obtain
......
---
title: Geo - Properly set tracking database connection and cron jobs on secondary nodes
merge_request:
author:
---
title: Allow to view Personal pipelines quota
merge_request:
author:
---
title: Add closed_at field to issue CSV export
merge_request:
author:
...@@ -622,6 +622,12 @@ production: &base ...@@ -622,6 +622,12 @@ production: &base
# host: localhost # host: localhost
# port: 3808 # port: 3808
## GitLab Geo settings (EE-only)
geo_primary_role:
enabled: false
geo_secondary_role:
enabled: false
# #
# 5. Extra customization # 5. Extra customization
# ========================== # ==========================
...@@ -705,6 +711,10 @@ test: ...@@ -705,6 +711,10 @@ test:
user_filter: '' user_filter: ''
group_base: 'ou=groups,dc=example,dc=com' group_base: 'ou=groups,dc=example,dc=com'
admin_group: '' admin_group: ''
geo_primary_role:
enabled: true
geo_secondary_role:
enabled: true
staging: staging:
<<: *base <<: *base
...@@ -342,6 +342,10 @@ Settings.pages['external_https'] ||= false unless Settings.pages['external_http ...@@ -342,6 +342,10 @@ Settings.pages['external_https'] ||= false unless Settings.pages['external_http
# Geo # Geo
# #
Settings.gitlab['geo_status_timeout'] ||= 10 Settings.gitlab['geo_status_timeout'] ||= 10
Settings['geo_primary_role'] ||= Settingslogic.new({})
Settings.geo_primary_role['enabled'] = false if Settings.geo_primary_role['enabled'].nil?
Settings['geo_secondary_role'] ||= Settingslogic.new({})
Settings.geo_secondary_role['enabled'] = false if Settings.geo_secondary_role['enabled'].nil?
# #
# Git LFS # Git LFS
......
if File.exist?(Rails.root.join('config/database_geo.yml')) if Gitlab::Geo.secondary_role_enabled?
Rails.application.configure do Rails.application.configure do
config.geo_database = config_for(:database_geo) config.geo_database = config_for(:database_geo)
end end
......
...@@ -47,5 +47,9 @@ resource :profile, only: [:show, :update] do ...@@ -47,5 +47,9 @@ resource :profile, only: [:show, :update] do
end end
resources :u2f_registrations, only: [:destroy] resources :u2f_registrations, only: [:destroy]
## EE-specific
resources :pipeline_quota, only: [:index]
## EE-specific
end end
end end
...@@ -31,6 +31,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d ...@@ -31,6 +31,7 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get :contributed, as: :contributed_projects get :contributed, as: :contributed_projects
get :snippets get :snippets
get :exists get :exists
get :pipelines_quota
get '/', to: redirect('/%{username}'), as: nil get '/', to: redirect('/%{username}'), as: nil
end end
......
...@@ -7,7 +7,7 @@ feature tests with Capybara for e2e (end-to-end) integration testing. ...@@ -7,7 +7,7 @@ feature tests with Capybara for e2e (end-to-end) integration testing.
Unit and feature tests need to be written for all new features. Unit and feature tests need to be written for all new features.
Most of the time, you should use rspec for your feature tests. Most of the time, you should use rspec for your feature tests.
There are cases where the behaviour you are testing is not worth the time spent running the full application, There are cases where the behaviour you are testing is not worth the time spent running the full application,
for example, if you are testing styling, animation or small actions that don't involve the backend, for example, if you are testing styling, animation, edge cases or small actions that don't involve the backend,
you should write an integration test using Jasmine. you should write an integration test using Jasmine.
![Testing priority triangle](img/testing_triangle.png) ![Testing priority triangle](img/testing_triangle.png)
......
...@@ -35,7 +35,6 @@ module API ...@@ -35,7 +35,6 @@ module API
get 'status' do get 'status' do
authenticate_by_gitlab_geo_node_token! authenticate_by_gitlab_geo_node_token!
require_node_to_be_secondary! require_node_to_be_secondary!
require_node_to_have_tracking_db!
present GeoNodeStatus.new(id: Gitlab::Geo.current_node.id), with: Entities::GeoNodeStatus present GeoNodeStatus.new(id: Gitlab::Geo.current_node.id), with: Entities::GeoNodeStatus
end end
...@@ -110,10 +109,6 @@ module API ...@@ -110,10 +109,6 @@ module API
def require_node_to_be_secondary! def require_node_to_be_secondary!
forbidden! 'Geo node is not secondary node.' unless Gitlab::Geo.current_node&.secondary? forbidden! 'Geo node is not secondary node.' unless Gitlab::Geo.current_node&.secondary?
end end
def require_node_to_have_tracking_db!
not_found! 'Geo node does not have its tracking database enabled.' unless Gitlab::Geo.configured?
end
end end
end end
end end
...@@ -42,8 +42,12 @@ module Gitlab ...@@ -42,8 +42,12 @@ module Gitlab
Gitlab::Geo.current_node.reload.enabled? Gitlab::Geo.current_node.reload.enabled?
end end
def self.configured? def self.primary_role_enabled?
Rails.configuration.respond_to?(:geo_database) Gitlab.config.geo_primary_role['enabled']
end
def self.secondary_role_enabled?
Gitlab.config.geo_secondary_role['enabled']
end end
def self.license_allows? def self.license_allows?
...@@ -94,9 +98,9 @@ module Gitlab ...@@ -94,9 +98,9 @@ module Gitlab
end end
def self.configure_cron_jobs! def self.configure_cron_jobs!
if self.primary? if self.primary_role_enabled?
self.configure_primary_jobs! self.configure_primary_jobs!
elsif self.secondary? elsif self.secondary_role_enabled?
self.configure_secondary_jobs! self.configure_secondary_jobs!
else else
self.disable_all_jobs! self.disable_all_jobs!
......
...@@ -3,7 +3,8 @@ module Gitlab ...@@ -3,7 +3,8 @@ module Gitlab
class HealthCheck class HealthCheck
def self.perform_checks def self.perform_checks
return '' unless Gitlab::Geo.secondary? return '' unless Gitlab::Geo.secondary?
return 'The Geo database configuration file is missing.' unless Gitlab::Geo.configured? return 'The Geo secondary role is disabled.' unless Gitlab::Geo.secondary_role_enabled?
return 'The Geo database configuration file is missing.' unless self.geo_database_configured?
return 'The Geo node has a database that is not configured for streaming replication with the primary node.' unless self.database_secondary? return 'The Geo node has a database that is not configured for streaming replication with the primary node.' unless self.database_secondary?
database_version = self.get_database_version.to_i database_version = self.get_database_version.to_i
...@@ -57,6 +58,10 @@ module Gitlab ...@@ -57,6 +58,10 @@ module Gitlab
.first .first
.fetch('pg_is_in_recovery') == 't' .fetch('pg_is_in_recovery') == 't'
end end
def self.geo_database_configured?
Rails.configuration.respond_to?(:geo_database)
end
end end
end end
end end
require 'spec_helper'
feature 'Profile > Pipeline Quota', feature: true do
let(:user) { create(:user) }
let(:namespace) { create(:namespace, owner: user) }
let!(:project) { create(:empty_project, namespace: namespace, shared_runners_enabled: true) }
before do
login_with(user)
end
it 'is linked within the profile page' do
visit profile_path
page.within('.layout-nav') do
expect(page).to have_selector(:link_or_button, 'Pipeline quota')
end
end
context 'with no quota' do
let(:namespace) { create(:namespace, :with_build_minutes, owner: user) }
it 'shows correct group quota info' do
visit profile_pipeline_quota_path
page.within('.pipeline-quota') do
expect(page).to have_content("400 / Unlimited minutes")
expect(page).to have_selector('.progress-bar-success')
end
end
end
context 'with no projects using shared runners' do
let(:namespace) { create(:namespace, :with_not_used_build_minutes_limit, owner: user) }
let!(:project) { create(:empty_project, namespace: namespace, shared_runners_enabled: false) }
it 'shows correct group quota info' do
visit profile_pipeline_quota_path
page.within('.pipeline-quota') do
expect(page).to have_content("300 / Unlimited minutes")
expect(page).to have_selector('.progress-bar-success')
end
page.within('.pipeline-project-metrics') do
expect(page).to have_content('This group has no projects which use shared runners')
end
end
end
context 'minutes under quota' do
let(:namespace) { create(:namespace, :with_not_used_build_minutes_limit, owner: user) }
it 'shows correct group quota info' do
visit profile_pipeline_quota_path
page.within('.pipeline-quota') do
expect(page).to have_content("300 / 500 minutes")
expect(page).to have_content("60% used")
expect(page).to have_selector('.progress-bar-success')
end
end
end
context 'minutes over quota' do
let(:namespace) { create(:namespace, :with_used_build_minutes_limit, owner: user) }
let!(:other_project) { create(:empty_project, namespace: namespace, shared_runners_enabled: false) }
it 'shows correct group quota and projects info' do
visit profile_pipeline_quota_path
page.within('.pipeline-quota') do
expect(page).to have_content("1000 / 500 minutes")
expect(page).to have_content("200% used")
expect(page).to have_selector('.progress-bar-danger')
end
page.within('.pipeline-project-metrics') do
expect(page).to have_content(project.name)
expect(page).not_to have_content(other_project.name)
end
end
end
end
...@@ -41,7 +41,7 @@ describe 'Project settings > [EE] repository', feature: true do ...@@ -41,7 +41,7 @@ describe 'Project settings > [EE] repository', feature: true do
end end
it 'sets mirror user' do it 'sets mirror user' do
page.within('.edit_project') do page.within('.project-mirror-settings') do
select2(user2.id, from: '#project_mirror_user_id') select2(user2.id, from: '#project_mirror_user_id')
click_button('Save changes') click_button('Save changes')
......
...@@ -16,6 +16,13 @@ describe Gitlab::Geo::HealthCheck do ...@@ -16,6 +16,13 @@ describe Gitlab::Geo::HealthCheck do
expect(subject.perform_checks).to be_blank expect(subject.perform_checks).to be_blank
end end
it 'returns an error when secondary role is disabled' do
allow(Gitlab::Geo).to receive(:secondary?) { true }
allow(Gitlab::Geo).to receive(:secondary_role_enabled?).and_return(false)
expect(subject.perform_checks).not_to be_blank
end
it 'returns an error when database is not configured for streaming replication' do it 'returns an error when database is not configured for streaming replication' do
allow(Gitlab::Geo).to receive(:secondary?) { true } allow(Gitlab::Geo).to receive(:secondary?) { true }
allow(Gitlab::Database).to receive(:postgresql?) { true } allow(Gitlab::Database).to receive(:postgresql?) { true }
......
...@@ -127,7 +127,9 @@ describe Gitlab::Geo, lib: true do ...@@ -127,7 +127,9 @@ describe Gitlab::Geo, lib: true do
end end
it 'activates cron jobs for primary' do it 'activates cron jobs for primary' do
allow(described_class).to receive(:primary?).and_return(true) allow(described_class).to receive(:primary_role_enabled?).and_return(true)
allow(described_class).to receive(:secondary_role_enabled?).and_return(false)
described_class.configure_cron_jobs! described_class.configure_cron_jobs!
expect(described_class.bulk_notify_job).to be_enabled expect(described_class.bulk_notify_job).to be_enabled
...@@ -136,7 +138,9 @@ describe Gitlab::Geo, lib: true do ...@@ -136,7 +138,9 @@ describe Gitlab::Geo, lib: true do
end end
it 'activates cron jobs for secondary' do it 'activates cron jobs for secondary' do
allow(described_class).to receive(:secondary?).and_return(true) allow(described_class).to receive(:primary_role_enabled?).and_return(false)
allow(described_class).to receive(:secondary_role_enabled?).and_return(true)
described_class.configure_cron_jobs! described_class.configure_cron_jobs!
expect(described_class.bulk_notify_job).not_to be_enabled expect(described_class.bulk_notify_job).not_to be_enabled
...@@ -145,6 +149,9 @@ describe Gitlab::Geo, lib: true do ...@@ -145,6 +149,9 @@ describe Gitlab::Geo, lib: true do
end end
it 'deactivates all jobs when Geo is not active' do it 'deactivates all jobs when Geo is not active' do
allow(described_class).to receive(:primary_role_enabled?).and_return(false)
allow(described_class).to receive(:secondary_role_enabled?).and_return(false)
described_class.configure_cron_jobs! described_class.configure_cron_jobs!
expect(described_class.bulk_notify_job).not_to be_enabled expect(described_class.bulk_notify_job).not_to be_enabled
......
...@@ -307,14 +307,6 @@ describe API::Geo, api: true do ...@@ -307,14 +307,6 @@ describe API::Geo, api: true do
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(response).to match_response_schema('geo_node_status') expect(response).to match_response_schema('geo_node_status')
end end
it 'responds with a 404 when the tracking database is disabled' do
allow(Gitlab::Geo).to receive(:configured?).and_return(false)
get api('/geo/status'), nil, request.headers
expect(response).to have_http_status(404)
end
end end
context 'when requesting primary node with valid auth header' do context 'when requesting primary node with valid auth header' do
......
...@@ -39,6 +39,7 @@ describe Issues::ExportCsvService, services: true do ...@@ -39,6 +39,7 @@ describe Issues::ExportCsvService, services: true do
due_date: DateTime.new(2014, 3, 2), due_date: DateTime.new(2014, 3, 2),
created_at: DateTime.new(2015, 4, 3, 2, 1, 0), created_at: DateTime.new(2015, 4, 3, 2, 1, 0),
updated_at: DateTime.new(2016, 5, 4, 3, 2, 1), updated_at: DateTime.new(2016, 5, 4, 3, 2, 1),
closed_at: DateTime.new(2017, 6, 5, 4, 3, 2),
labels: [feature_label, idea_label]) labels: [feature_label, idea_label])
end end
...@@ -101,6 +102,10 @@ describe Issues::ExportCsvService, services: true do ...@@ -101,6 +102,10 @@ describe Issues::ExportCsvService, services: true do
specify 'updated_at' do specify 'updated_at' do
expect(csv[0]['Updated At (UTC)']).to eq '2016-05-04 03:02:01' expect(csv[0]['Updated At (UTC)']).to eq '2016-05-04 03:02:01'
end end
specify 'closed_at' do
expect(csv[0]['Closed At (UTC)']).to eq '2017-06-05 04:03:02'
end
end end
context 'with minimal details' do context 'with minimal details' do
......
...@@ -13,10 +13,10 @@ describe GeoFileDownloadDispatchWorker do ...@@ -13,10 +13,10 @@ describe GeoFileDownloadDispatchWorker do
subject { described_class.new } subject { described_class.new }
describe '#perform' do describe '#perform' do
it 'does not schedule anything when tracking DB is not available' do it 'does not schedule anything when secondary role is disabled' do
create(:lfs_object, :with_file) create(:lfs_object, :with_file)
allow(Rails.configuration).to receive(:respond_to?).with(:geo_database) { false } allow(Gitlab::Geo).to receive(:secondary_role_enabled?) { false }
expect(GeoFileDownloadWorker).not_to receive(:perform_async) expect(GeoFileDownloadWorker).not_to receive(:perform_async)
......
...@@ -52,8 +52,8 @@ describe GeoRepositorySyncWorker do ...@@ -52,8 +52,8 @@ describe GeoRepositorySyncWorker do
subject.perform subject.perform
end end
it 'does not perform Geo::RepositorySyncService when tracking DB is not available' do it 'does not perform Geo::RepositorySyncService when secondary role is disabled' do
allow(Rails.configuration).to receive(:respond_to?).with(:geo_database) { false } allow(Gitlab::Geo).to receive(:secondary_role_enabled?) { false }
expect(Geo::RepositorySyncService).not_to receive(:new) expect(Geo::RepositorySyncService).not_to receive(:new)
......
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