...@@ -260,6 +260,10 @@ module Gitlab ...@@ -260,6 +260,10 @@ module Gitlab
caching_config_hash[:pool_timeout] = 1 caching_config_hash[:pool_timeout] = 1
end end
# Overrides RedisCacheStore's default value of 0
# This makes the default value the same with Gitlab::Redis::Cache
caching_config_hash[:reconnect_attempts] ||= ::Redis::Client::DEFAULTS[:reconnect_attempts]
config.cache_store = :redis_cache_store, caching_config_hash config.cache_store = :redis_cache_store, caching_config_hash
config.active_job.queue_adapter = :sidekiq config.active_job.queue_adapter = :sidekiq
... ...
......
...@@ -43,6 +43,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled? ...@@ -43,6 +43,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
defined?(::Prometheus::Client.reinitialize_on_pid_change) && Prometheus::Client.reinitialize_on_pid_change defined?(::Prometheus::Client.reinitialize_on_pid_change) && Prometheus::Client.reinitialize_on_pid_change
Gitlab::Metrics::Samplers::RubySampler.initialize_instance(Settings.monitoring.ruby_sampler_interval).start Gitlab::Metrics::Samplers::RubySampler.initialize_instance(Settings.monitoring.ruby_sampler_interval).start
rescue IOError => e
Gitlab::ErrorTracking.track_exception(e)
Gitlab::Metrics.error_detected!
end end
Gitlab::Cluster::LifecycleEvents.on_master_start do Gitlab::Cluster::LifecycleEvents.on_master_start do
...@@ -55,6 +58,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled? ...@@ -55,6 +58,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
end end
Gitlab::Metrics::RequestsRackMiddleware.initialize_http_request_duration_seconds Gitlab::Metrics::RequestsRackMiddleware.initialize_http_request_duration_seconds
rescue IOError => e
Gitlab::ErrorTracking.track_exception(e)
Gitlab::Metrics.error_detected!
end end
end end
... ...
......
...@@ -118,8 +118,7 @@ You must do the following: ...@@ -118,8 +118,7 @@ You must do the following:
1. Ensure GitLab can manage Knative: 1. Ensure GitLab can manage Knative:
- For a non-GitLab managed cluster, ensure that the service account for the token - For a non-GitLab managed cluster, ensure that the service account for the token
provided can manage resources in the `serving.knative.dev` API group. It will also provided can manage resources in the `serving.knative.dev` API group.
need list access to the deployments in the `knative-serving` namespace.
- For a GitLab managed cluster, if you added the cluster in [GitLab 12.1 or later](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/30235), - For a GitLab managed cluster, if you added the cluster in [GitLab 12.1 or later](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/30235),
then GitLab will already have the required access and you can proceed to the next step. then GitLab will already have the required access and you can proceed to the next step.
...@@ -156,19 +155,6 @@ You must do the following: ...@@ -156,19 +155,6 @@ You must do the following:
- delete - delete
- patch - patch
- watch - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gitlab-knative-version-role
rules:
- apiGroups:
- apps
resources:
- deployments
verbs:
- list
- get
``` ```
Then run the following command: Then run the following command:
... ...
......
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
def unmet? def unmet?
deployment_cluster.present? && deployment_cluster.present? &&
deployment_cluster.managed? && deployment_cluster.managed? &&
(missing_namespace? || need_knative_version_role_binding?) missing_namespace?
end end
def complete! def complete!
...@@ -23,10 +23,6 @@ module Gitlab ...@@ -23,10 +23,6 @@ module Gitlab
kubernetes_namespace.nil? || kubernetes_namespace.service_account_token.blank? kubernetes_namespace.nil? || kubernetes_namespace.service_account_token.blank?
end end
def need_knative_version_role_binding?
!knative_serving_namespace.nil? && knative_version_role_binding.nil?
end
def deployment_cluster def deployment_cluster
build.deployment&.cluster build.deployment&.cluster
end end
...@@ -35,22 +31,6 @@ module Gitlab ...@@ -35,22 +31,6 @@ module Gitlab
build.deployment.environment build.deployment.environment
end end
def knative_serving_namespace
strong_memoize(:knative_serving_namespace) do
Clusters::KnativeServingNamespaceFinder.new(
deployment_cluster
).execute
end
end
def knative_version_role_binding
strong_memoize(:knative_version_role_binding) do
Clusters::KnativeVersionRoleBindingFinder.new(
deployment_cluster
).execute
end
end
def kubernetes_namespace def kubernetes_namespace
strong_memoize(:kubernetes_namespace) do strong_memoize(:kubernetes_namespace) do
Clusters::KubernetesNamespaceFinder.new( Clusters::KubernetesNamespaceFinder.new(
... ...
......
...@@ -54,6 +54,11 @@ module Gitlab ...@@ -54,6 +54,11 @@ module Gitlab
def expose_as_present? def expose_as_present?
return false unless Feature.enabled?(:ci_expose_arbitrary_artifacts_in_mr, default_enabled: true) return false unless Feature.enabled?(:ci_expose_arbitrary_artifacts_in_mr, default_enabled: true)
# This duplicates the `validates :config, type: Hash` above,
# but Validatable currently doesn't halt the validation
# chain if it encounters a validation error.
return false unless @config.is_a?(Hash)
!@config[:expose_as].nil? !@config[:expose_as].nil?
end end
end end
... ...
......
# frozen_string_literal: true
module Gitlab
module Kubernetes
class ClusterRole
attr_reader :name, :rules
def initialize(name:, rules:)
@name = name
@rules = rules
end
def generate
::Kubeclient::Resource.new(
metadata: metadata,
rules: rules
)
end
private
def metadata
{
name: name
}
end
end
end
end
...@@ -56,7 +56,6 @@ module Gitlab ...@@ -56,7 +56,6 @@ module Gitlab
# group client # group client
delegate :create_cluster_role_binding, delegate :create_cluster_role_binding,
:get_cluster_role_binding, :get_cluster_role_binding,
:get_cluster_role_bindings,
:update_cluster_role_binding, :update_cluster_role_binding,
to: :rbac_client to: :rbac_client
...@@ -67,13 +66,6 @@ module Gitlab ...@@ -67,13 +66,6 @@ module Gitlab
:update_role, :update_role,
to: :rbac_client to: :rbac_client
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client
delegate :create_cluster_role,
:get_cluster_role,
:update_cluster_role,
to: :rbac_client
# RBAC methods delegates to the apis/rbac.authorization.k8s.io api # RBAC methods delegates to the apis/rbac.authorization.k8s.io api
# group client # group client
delegate :create_role_binding, delegate :create_role_binding,
... ...
......
...@@ -5,8 +5,14 @@ module Gitlab ...@@ -5,8 +5,14 @@ module Gitlab
include Gitlab::Metrics::InfluxDb include Gitlab::Metrics::InfluxDb
include Gitlab::Metrics::Prometheus include Gitlab::Metrics::Prometheus
@error = false
def self.enabled? def self.enabled?
influx_metrics_enabled? || prometheus_metrics_enabled? influx_metrics_enabled? || prometheus_metrics_enabled?
end end
def self.error?
@error
end
end end
end end
...@@ -61,6 +61,22 @@ module Gitlab ...@@ -61,6 +61,22 @@ module Gitlab
safe_provide_metric(:histogram, name, docstring, base_labels, buckets) safe_provide_metric(:histogram, name, docstring, base_labels, buckets)
end end
def error_detected!
set_error!(true)
end
def clear_errors!
set_error!(false)
end
def set_error!(status)
clear_memoization(:prometheus_metrics_enabled)
PROVIDER_MUTEX.synchronize do
@error = status
end
end
private private
def safe_provide_metric(method, name, *args) def safe_provide_metric(method, name, *args)
...@@ -81,7 +97,7 @@ module Gitlab ...@@ -81,7 +97,7 @@ module Gitlab
end end
def prometheus_metrics_enabled_unmemoized def prometheus_metrics_enabled_unmemoized
metrics_folder_present? && Gitlab::CurrentSettings.prometheus_metrics_enabled || false !error? && metrics_folder_present? && Gitlab::CurrentSettings.prometheus_metrics_enabled || false
end end
end end
end end
... ...
......
...@@ -2,10 +2,16 @@ ...@@ -2,10 +2,16 @@
module Gitlab module Gitlab
module Plugin module Plugin
def self.any?
plugin_glob.any? { |entry| File.file?(entry) }
end
def self.files def self.files
Dir.glob(Rails.root.join('plugins/*')).select do |entry| plugin_glob.select { |entry| File.file?(entry) }
File.file?(entry)
end end
def self.plugin_glob
Dir.glob(Rails.root.join('plugins/*'))
end end
def self.execute_all_async(data) def self.execute_all_async(data)
... ...
......
...@@ -26,6 +26,19 @@ def emit_errors(static_analysis) ...@@ -26,6 +26,19 @@ def emit_errors(static_analysis)
end end
end end
ALLOWED_WARNINGS = [
# https://github.com/browserslist/browserslist/blob/d0ec62eb48c41c218478cd3ac28684df051cc865/node.js#L329
# warns if caniuse-lite package is older than 6 months. Ignore this
# warning message so that GitLab backports don't fail.
"Browserslist: caniuse-lite is outdated. Please run next command `yarn upgrade`"
].freeze
def warning_count(static_analysis)
static_analysis.warned_results
.reject { |result| ALLOWED_WARNINGS.include?(result.stderr.strip) }
.count
end
def jobs_to_run(node_index, node_total) def jobs_to_run(node_index, node_total)
all_tasks = [ all_tasks = [
%w[bin/rake lint:all], %w[bin/rake lint:all],
...@@ -81,7 +94,7 @@ elsif static_analysis.all_success? ...@@ -81,7 +94,7 @@ elsif static_analysis.all_success?
emit_warnings(static_analysis) emit_warnings(static_analysis)
exit 2 exit 2 if warning_count(static_analysis).nonzero?
else else
puts 'Some static analyses failed:' puts 'Some static analyses failed:'
... ...
......
...@@ -318,6 +318,7 @@ describe 'Issue Boards', :js do ...@@ -318,6 +318,7 @@ describe 'Issue Boards', :js do
wait_for_requests wait_for_requests
click_link bug.title click_link bug.title
within('.dropdown-menu-labels') { expect(page).to have_selector('.is-active', count: 3) }
click_link regression.title click_link regression.title
wait_for_requests wait_for_requests
... ...
......
...@@ -57,4 +57,14 @@ describe 'User views releases', :js do ...@@ -57,4 +57,14 @@ describe 'User views releases', :js do
expect(page).to have_content('Upcoming Release') expect(page).to have_content('Upcoming Release')
end end
end end
context 'with a tag containing a slash' do
it 'sees the release' do
release = create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1'
visit project_releases_path(project)
expect(page).to have_content(release.name)
expect(page).to have_content(release.tag)
end
end
end end
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::KnativeServingNamespaceFinder do
include KubernetesHelpers
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:service) { environment.deployment_platform }
let(:project) { cluster.cluster_project.project }
let(:environment) { create(:environment, project: project) }
subject { described_class.new(cluster) }
before do
stub_kubeclient_discover(service.api_url)
end
it 'finds the namespace in a cluster where it exists' do
stub_kubeclient_get_namespace(service.api_url, namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE)
expect(subject.execute).to be_a Kubeclient::Resource
end
it 'returns nil in a cluster where it does not' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [404, "Resource Not Found"]
}
)
expect(subject.execute).to be nil
end
it 'returns nil in a cluster where the lookup results in a 403 as it will in some versions of kubernetes' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [403, "Resource Not Found"]
}
)
expect(subject.execute).to be nil
end
it 'raises an error if error code is not 404 or 403' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [500, "Internal Server Error"]
}
)
expect { subject.execute }.to raise_error(Kubeclient::HttpError)
end
end
...@@ -38,36 +38,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do ...@@ -38,36 +38,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
.and_return(double(execute: kubernetes_namespace)) .and_return(double(execute: kubernetes_namespace))
end end
context 'and the knative-serving namespace is missing' do
before do
allow(Clusters::KnativeServingNamespaceFinder).to receive(:new)
.and_return(double(execute: false))
end
it { is_expected.to be_truthy }
end
context 'and the knative-serving namespace exists' do
before do
allow(Clusters::KnativeServingNamespaceFinder).to receive(:new)
.and_return(double(execute: true))
end
context 'and the knative version role binding is missing' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
end
it { is_expected.to be_truthy }
end
context 'and the knative version role binding already exists' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: true))
end
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
context 'and the service_account_token is blank' do context 'and the service_account_token is blank' do
...@@ -77,8 +47,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do ...@@ -77,8 +47,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
end end
end end
end end
end
end
context 'and no cluster to deploy to' do context 'and no cluster to deploy to' do
let(:cluster) { nil } let(:cluster) { nil }
...@@ -188,24 +156,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do ...@@ -188,24 +156,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
subject subject
end end
end end
context 'knative version role binding is missing' do
before do
allow(Clusters::KubernetesNamespaceFinder).to receive(:new)
.and_return(double(execute: kubernetes_namespace))
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
end
it 'creates the knative version role binding' do
expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService)
.to receive(:new)
.with(cluster: cluster, kubernetes_namespace: kubernetes_namespace)
.and_return(service)
subject
end
end
end end
context 'completion is not required' do context 'completion is not required' do
... ...
......
...@@ -1255,6 +1255,19 @@ module Gitlab ...@@ -1255,6 +1255,19 @@ module Gitlab
expect(builds.first[:options][:artifacts][:when]).to eq(when_state) expect(builds.first[:options][:artifacts][:when]).to eq(when_state)
end end
end end
it "gracefully handles errors in artifacts type" do
config = <<~YAML
test:
script:
- echo "Hello world"
artifacts:
- paths:
- test/
YAML
expect { described_class.new(config) }.to raise_error(described_class::ValidationError)
end
end end
describe '#environment' do describe '#environment' do
... ...
......
...@@ -6,6 +6,10 @@ describe Gitlab::Metrics::Prometheus, :prometheus do ...@@ -6,6 +6,10 @@ describe Gitlab::Metrics::Prometheus, :prometheus do
let(:all_metrics) { Gitlab::Metrics } let(:all_metrics) { Gitlab::Metrics }
let(:registry) { all_metrics.registry } let(:registry) { all_metrics.registry }
after do
all_metrics.clear_errors!
end
describe '#reset_registry!' do describe '#reset_registry!' do
it 'clears existing metrics' do it 'clears existing metrics' do
registry.counter(:test, 'test metric') registry.counter(:test, 'test metric')
...@@ -17,4 +21,21 @@ describe Gitlab::Metrics::Prometheus, :prometheus do ...@@ -17,4 +21,21 @@ describe Gitlab::Metrics::Prometheus, :prometheus do
expect(all_metrics.registry.metrics.count).to eq(0) expect(all_metrics.registry.metrics.count).to eq(0)
end end
end end
describe '#error_detected!' do
before do
allow(all_metrics).to receive(:metrics_folder_present?).and_return(true)
stub_application_setting(prometheus_metrics_enabled: true)
end
it 'disables Prometheus metrics' do
expect(all_metrics.error?).to be_falsey
expect(all_metrics.prometheus_metrics_enabled?).to be_truthy
all_metrics.error_detected!
expect(all_metrics.prometheus_metrics_enabled?).to be_falsey
expect(all_metrics.error?).to be_truthy
end
end
end end
...@@ -3,13 +3,8 @@ ...@@ -3,13 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Plugin do describe Gitlab::Plugin do
describe '.execute' do
let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA }
let(:plugin) { Rails.root.join('plugins', 'test.rb') } let(:plugin) { Rails.root.join('plugins', 'test.rb') }
let(:tmp_file) { Tempfile.new('plugin-dump') } let(:tmp_file) { Tempfile.new('plugin-dump') }
let(:result) { described_class.execute(plugin.to_s, data) }
let(:success) { result.first }
let(:message) { result.last }
let(:plugin_source) do let(:plugin_source) do
<<~EOS <<~EOS
...@@ -19,6 +14,48 @@ describe Gitlab::Plugin do ...@@ -19,6 +14,48 @@ describe Gitlab::Plugin do
EOS EOS
end end
context 'with plugins present' do
before do
File.write(plugin, plugin_source)
end
after do
FileUtils.rm(plugin)
end
describe '.any?' do
it 'returns true' do
expect(described_class.any?).to be true
end
end
describe '.files?' do
it 'returns a list of plugins' do
expect(described_class.files).to match_array([plugin.to_s])
end
end
end
context 'without any plugins' do
describe '.any?' do
it 'returns false' do
expect(described_class.any?).to be false
end
end
describe '.files' do
it 'returns an empty list' do
expect(described_class.files).to be_empty
end
end
end
describe '.execute' do
let(:data) { Gitlab::DataBuilder::Push::SAMPLE_DATA }
let(:result) { described_class.execute(plugin.to_s, data) }
let(:success) { result.first }
let(:message) { result.last }
before do before do
File.write(plugin, plugin_source) File.write(plugin, plugin_source)
end end
... ...
......
...@@ -4714,6 +4714,13 @@ describe Project do ...@@ -4714,6 +4714,13 @@ describe Project do
expect(project.has_active_hooks?(:merge_request_events)).to be_falsey expect(project.has_active_hooks?(:merge_request_events)).to be_falsey
expect(project.has_active_hooks?).to be_truthy expect(project.has_active_hooks?).to be_truthy
end end
it 'returns true when a plugin exists' do
expect(Gitlab::Plugin).to receive(:any?).twice.and_return(true)
expect(project.has_active_hooks?(:merge_request_events)).to be_truthy
expect(project.has_active_hooks?).to be_truthy
end
end end
describe '#has_active_services?' do describe '#has_active_services?' do
... ...
......
...@@ -96,4 +96,28 @@ describe ReleasePresenter do ...@@ -96,4 +96,28 @@ describe ReleasePresenter do
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
end end
describe '#evidence_file_path' do
subject { presenter.evidence_file_path }
context 'without evidence' do
it { is_expected.to be_falsy }
end
context 'with evidence' do
let(:release) { create :release, :with_evidence, project: project }
specify do
is_expected.to match /#{evidence_project_release_url(project, release.tag, format: :json)}/
end
end
context 'when a tag contains a slash' do
let(:release) { create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1' }
specify do
is_expected.to match /#{evidence_project_release_url(project, CGI.escape(release.tag), format: :json)}/
end
end
end
end end