summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js4
-rw-r--r--app/assets/javascripts/boards/services/board_service.js5
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue51
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue41
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue6
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_actions.vue25
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.vue22
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue3
-rw-r--r--app/assets/stylesheets/framework/responsive_tables.scss2
-rw-r--r--app/controllers/concerns/issuable_collections.rb5
-rw-r--r--app/finders/clusters/knative_services_finder.rb16
-rw-r--r--app/finders/clusters/kubernetes_namespace_finder.rb36
-rw-r--r--app/finders/projects/serverless/functions_finder.rb70
-rw-r--r--app/models/clusters/applications/prometheus.rb2
-rw-r--r--app/models/clusters/cluster.rb52
-rw-r--r--app/models/clusters/kubernetes_namespace.rb31
-rw-r--r--app/models/clusters/platforms/kubernetes.rb32
-rw-r--r--app/models/concerns/prometheus_adapter.rb6
-rw-r--r--app/models/deploy_key.rb6
-rw-r--r--app/models/deploy_keys_project.rb3
-rw-r--r--app/models/environment.rb9
-rw-r--r--app/models/list.rb3
-rw-r--r--app/models/merge_request_diff.rb6
-rw-r--r--app/models/project.rb19
-rw-r--r--app/models/project_services/mock_deployment_service.rb2
-rw-r--r--app/models/project_services/prometheus_service.rb9
-rw-r--r--app/models/user.rb11
-rw-r--r--app/presenters/blob_presenter.rb19
-rw-r--r--app/presenters/blobs/unfold_presenter.rb23
-rw-r--r--app/presenters/projects/settings/deploy_keys_presenter.rb40
-rw-r--r--app/serializers/deploy_key_entity.rb7
-rw-r--r--app/services/clusters/build_kubernetes_namespace_service.rb35
-rw-r--r--app/services/clusters/create_service.rb7
-rw-r--r--app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb5
-rw-r--r--app/services/prometheus/proxy_service.rb2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml5
-rw-r--r--app/views/projects/_export.html.haml1
-rw-r--r--app/workers/chaos/kill_worker.rb2
39 files changed, 370 insertions, 255 deletions
diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index 35874140bf9..b2571fb840c 100644
--- a/app/assets/javascripts/behaviors/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
@@ -36,6 +36,10 @@ MarkdownPreview.prototype.showPreview = function($form) {
mdText = $form.find('textarea.markdown-area').val();
+ if (mdText === undefined) {
+ return;
+ }
+
if (mdText.trim().length === 0) {
preview.text(this.emptyMessage);
this.hideReferencedUsers($form);
diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js
index 5202620057c..56a6cab6c73 100644
--- a/app/assets/javascripts/boards/services/board_service.js
+++ b/app/assets/javascripts/boards/services/board_service.js
@@ -1,4 +1,9 @@
/* eslint-disable class-methods-use-this */
+/**
+ * This file is intended to be deleted.
+ * The existing functions will removed one by one in favor of using the board store directly.
+ * see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621
+ */
import boardsStore from '~/boards/stores/boards_store';
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 45543ef2cc8..2feb545199b 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -1,5 +1,12 @@
<script>
-import { GlButton, GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlModal,
+ GlModalDirective,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
@@ -30,7 +37,8 @@ export default {
GlModal,
},
directives: {
- GlModalDirective,
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
},
props: {
externalDashboardUrl: {
@@ -328,7 +336,7 @@ export default {
<div class="d-flex">
<div v-if="addingMetricsAvailable">
<gl-button
- v-gl-modal-directive="$options.addMetric.modalId"
+ v-gl-modal="$options.addMetric.modalId"
class="js-add-metric-button text-success border-success"
>{{ $options.addMetric.title }}</gl-button
>
@@ -395,14 +403,35 @@ export default {
:project-path="projectPath"
group-id="monitor-area-chart"
>
- <alert-widget
- v-if="alertWidgetAvailable && graphData"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.queries"
- :alerts-to-manage="getGraphAlerts(graphData.queries)"
- :modal-id="`alert-modal-${index}-${graphIndex}`"
- @setAlerts="setAlerts"
- />
+ <div class="d-flex align-items-center">
+ <alert-widget
+ v-if="alertWidgetAvailable && graphData"
+ :modal-id="`alert-modal-${index}-${graphIndex}`"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.queries"
+ :alerts-to-manage="getGraphAlerts(graphData.queries)"
+ @setAlerts="setAlerts"
+ />
+ <gl-dropdown
+ v-if="alertWidgetAvailable"
+ v-gl-tooltip
+ class="mx-2"
+ toggle-class="btn btn-transparent border-0"
+ :right="true"
+ :no-caret="true"
+ :title="__('More actions')"
+ >
+ <template slot="button-content">
+ <icon name="ellipsis_v" class="text-secondary" />
+ </template>
+ <gl-dropdown-item
+ v-if="alertWidgetAvailable"
+ v-gl-modal="`alert-modal-${index}-${graphIndex}`"
+ >
+ {{ __('Alerts') }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
</monitor-area-chart>
</template>
</graph-group>
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index f1f02964a29..295c0851f12 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -1,6 +1,7 @@
<script>
import { mapState } from 'vuex';
import _ from 'underscore';
+import { GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui';
import MonitorAreaChart from './charts/area.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
@@ -10,6 +11,12 @@ export default {
MonitorAreaChart,
MonitorSingleStatChart,
MonitorEmptyChart,
+ GlDropdown,
+ GlDropdownItem,
+ GlModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
},
props: {
graphData: {
@@ -64,14 +71,32 @@ export default {
:container-width="dashboardWidth"
group-id="monitor-area-chart"
>
- <alert-widget
- v-if="alertWidgetAvailable"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.queries"
- :alerts-to-manage="getGraphAlerts(graphData.queries)"
- :modal-id="`alert-modal-${index}`"
- @setAlerts="setAlerts"
- />
+ <div class="d-flex align-items-center">
+ <alert-widget
+ v-if="alertWidgetAvailable && graphData"
+ :modal-id="`alert-modal-${index}`"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.queries"
+ :alerts-to-manage="getGraphAlerts(graphData.queries)"
+ @setAlerts="setAlerts"
+ />
+ <gl-dropdown
+ v-if="alertWidgetAvailable"
+ v-gl-tooltip
+ class="mx-2"
+ toggle-class="btn btn-transparent border-0"
+ :right="true"
+ :no-caret="true"
+ :title="__('More actions')"
+ >
+ <template slot="button-content">
+ <icon name="ellipsis_v" class="text-secondary" />
+ </template>
+ <gl-dropdown-item v-if="alertWidgetAvailable" v-gl-modal="`alert-modal-${index}`">
+ {{ __('Alerts') }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
</monitor-area-chart>
<monitor-empty-chart v-else :graph-title="graphData.title" />
</template>
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index c0ea42ad1a2..13aa8844172 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -112,12 +112,6 @@ export default {
:header="metric.header"
:keys="metric.keys"
/>
- <div id="peek-view-gc" class="view">
- <span v-if="currentRequest.details" class="bold">
- <span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span
- >ms / <span title="Invoke Count">{{ currentRequest.details.gc.invokes }}</span> gc
- </span>
- </div>
<div
v-if="currentRequest.details && currentRequest.details.tracing"
id="peek-view-trace"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
index 244d332f38f..4b2d816c6a0 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
@@ -1,9 +1,11 @@
<script>
import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
-import { s__, sprintf } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import flash from '~/flash';
+import { s__, __, sprintf } from '~/locale';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
-import Icon from '../../vue_shared/components/icon.vue';
export default {
directives: {
@@ -44,7 +46,24 @@ export default {
this.isLoading = true;
- eventHub.$emit('postAction', action.path);
+ /**
+ * Ideally, the component would not make an api call directly.
+ * However, in order to use the eventhub and know when to
+ * toggle back the `isLoading` property we'd need an ID
+ * to track the request with a wacther - since this component
+ * is rendered at least 20 times in the same page, moving the
+ * api call directly here is the most performant solution
+ */
+ axios
+ .post(`${action.path}.json`)
+ .then(() => {
+ this.isLoading = false;
+ eventHub.$emit('updateTable');
+ })
+ .catch(() => {
+ this.isLoading = false;
+ flash(__('An error occurred while making the request.'));
+ });
},
isActionDisabled(action) {
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js
index a6243366375..126a9a47a2b 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines.js
@@ -60,12 +60,14 @@ export default {
eventHub.$on('postAction', this.postAction);
eventHub.$on('retryPipeline', this.postAction);
eventHub.$on('clickedDropdown', this.updateTable);
+ eventHub.$on('updateTable', this.updateTable);
eventHub.$on('refreshPipelinesTable', this.fetchPipelines);
},
beforeDestroy() {
eventHub.$off('postAction', this.postAction);
eventHub.$off('retryPipeline', this.postAction);
eventHub.$off('clickedDropdown', this.updateTable);
+ eventHub.$off('updateTable', this.updateTable);
eventHub.$off('refreshPipelinesTable', this.fetchPipelines);
},
destroyed() {
diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue
index ae9b013d980..f7c508c4e23 100644
--- a/app/assets/javascripts/vue_shared/components/commit.vue
+++ b/app/assets/javascripts/vue_shared/components/commit.vue
@@ -152,37 +152,35 @@ export default {
:href="mergeRequestRef.path"
:title="mergeRequestRef.title"
class="ref-name"
+ >{{ mergeRequestRef.iid }}</gl-link
>
- {{ mergeRequestRef.iid }}
- </gl-link>
<gl-link
v-else
v-gl-tooltip
:href="commitRef.ref_url"
:title="commitRef.name"
class="ref-name"
+ >{{ commitRef.name }}</gl-link
>
- {{ commitRef.name }}
- </gl-link>
</template>
<icon name="commit" class="commit-icon js-commit-icon" />
- <gl-link :href="commitUrl" class="commit-sha mr-0"> {{ shortSha }} </gl-link>
+ <gl-link :href="commitUrl" class="commit-sha mr-0">{{ shortSha }}</gl-link>
- <div class="commit-title flex-truncate-parent">
- <tooltip-on-truncate v-if="title" class="flex-truncate-child" :title="title">
+ <div class="commit-title">
+ <span v-if="title" class="flex-truncate-parent">
<user-avatar-link
v-if="hasAuthor"
:link-href="author.path"
:img-src="author.avatar_url"
:img-alt="userImageAltDescription"
:tooltip-text="author.username"
- class="avatar-image-container"
+ class="avatar-image-container text-decoration-none"
/>
- <gl-link :href="commitUrl" class="commit-row-message cgray">
- {{ title }}
- </gl-link>
- </tooltip-on-truncate>
+ <tooltip-on-truncate :title="title" class="flex-truncate-child">
+ <gl-link :href="commitUrl" class="commit-row-message cgray">{{ title }}</gl-link>
+ </tooltip-on-truncate>
+ </span>
<span v-else>{{ __("Can't find HEAD commit for this branch") }}</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
index fc6a45b957e..6a4a834337a 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
@@ -27,7 +27,6 @@ export default {
return {
width: 0,
height: 0,
- isLoaded: false,
};
},
computed: {
@@ -63,8 +62,6 @@ export default {
this.height = contentImg.naturalHeight;
this.$nextTick(() => {
- this.isLoaded = true;
-
this.$emit('imgLoaded', {
width: this.width,
height: this.height,
diff --git a/app/assets/stylesheets/framework/responsive_tables.scss b/app/assets/stylesheets/framework/responsive_tables.scss
index 6bd44ee19bd..fd6f80e26cb 100644
--- a/app/assets/stylesheets/framework/responsive_tables.scss
+++ b/app/assets/stylesheets/framework/responsive_tables.scss
@@ -155,7 +155,7 @@
text-overflow: ellipsis;
@include media-breakpoint-up(md) {
- flex: 0 0 90%;
+ flex: 0 0 85%;
}
.avatar {
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 21b3949e361..3489ea78b77 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -194,10 +194,9 @@ module IssuableCollections
end
def collection_type
- @collection_type ||= case finder_type.name
- when 'IssuesFinder'
+ @collection_type ||= if finder_type <= IssuesFinder
'Issue'
- when 'MergeRequestsFinder'
+ elsif finder_type <= MergeRequestsFinder
'MergeRequest'
end
end
diff --git a/app/finders/clusters/knative_services_finder.rb b/app/finders/clusters/knative_services_finder.rb
index 7d3b53ef663..71cebe4495e 100644
--- a/app/finders/clusters/knative_services_finder.rb
+++ b/app/finders/clusters/knative_services_finder.rb
@@ -13,11 +13,11 @@ module Clusters
self.reactive_cache_key = ->(finder) { finder.model_name }
self.reactive_cache_worker_finder = ->(_id, *cache_args) { from_cache(*cache_args) }
- attr_reader :cluster, :project
+ attr_reader :cluster, :environment
- def initialize(cluster, project)
+ def initialize(cluster, environment)
@cluster = cluster
- @project = project
+ @environment = environment
end
def with_reactive_cache_memoized(*cache_args, &block)
@@ -30,11 +30,11 @@ module Clusters
clear_reactive_cache!(*cache_args)
end
- def self.from_cache(cluster_id, project_id)
+ def self.from_cache(cluster_id, environment_id)
cluster = Clusters::Cluster.find(cluster_id)
- project = ::Project.find(project_id)
+ environment = Environment.find(environment_id)
- new(cluster, project)
+ new(cluster, environment)
end
def calculate_reactive_cache(*)
@@ -56,7 +56,7 @@ module Clusters
end
def cache_args
- [cluster.id, project.id]
+ [cluster.id, environment.id]
end
def service_pod_details(service)
@@ -84,7 +84,7 @@ module Clusters
private
def search_namespace
- @search_namespace ||= cluster.kubernetes_namespace_for(project)
+ @search_namespace ||= cluster.kubernetes_namespace_for(environment)
end
def knative_client
diff --git a/app/finders/clusters/kubernetes_namespace_finder.rb b/app/finders/clusters/kubernetes_namespace_finder.rb
new file mode 100644
index 00000000000..e947796c1e7
--- /dev/null
+++ b/app/finders/clusters/kubernetes_namespace_finder.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Clusters
+ class KubernetesNamespaceFinder
+ attr_reader :cluster, :project, :environment_slug
+
+ def initialize(cluster, project:, environment_slug:, allow_blank_token: false)
+ @cluster = cluster
+ @project = project
+ @environment_slug = environment_slug
+ @allow_blank_token = allow_blank_token
+ end
+
+ def execute
+ find_namespace(with_environment: cluster.namespace_per_environment?)
+ end
+
+ private
+
+ attr_reader :allow_blank_token
+
+ def find_namespace(with_environment:)
+ relation = with_environment ? namespaces.with_environment_slug(environment_slug) : namespaces
+
+ relation.find_by_project_id(project.id)
+ end
+
+ def namespaces
+ if allow_blank_token
+ cluster.kubernetes_namespaces
+ else
+ cluster.kubernetes_namespaces.has_service_account_token
+ end
+ end
+ end
+end
diff --git a/app/finders/projects/serverless/functions_finder.rb b/app/finders/projects/serverless/functions_finder.rb
index ebe50806ca1..e8c50ef1a88 100644
--- a/app/finders/projects/serverless/functions_finder.rb
+++ b/app/finders/projects/serverless/functions_finder.rb
@@ -3,10 +3,11 @@
module Projects
module Serverless
class FunctionsFinder
+ include Gitlab::Utils::StrongMemoize
+
attr_reader :project
def initialize(project)
- @clusters = project.clusters
@project = project
end
@@ -16,9 +17,8 @@ module Projects
# Possible return values: Clusters::KnativeServicesFinder::KNATIVE_STATE
def knative_installed
- states = @clusters.map do |cluster|
- cluster.application_knative
- cluster.knative_services_finder(project).knative_detected.tap do |state|
+ states = services_finders.map do |finder|
+ finder.knative_detected.tap do |state|
return state if state == ::Clusters::KnativeServicesFinder::KNATIVE_STATES['checking'] # rubocop:disable Cop/AvoidReturnFromBlocks
end
end
@@ -31,66 +31,70 @@ module Projects
end
def invocation_metrics(environment_scope, name)
- return unless prometheus_adapter&.can_query?
+ environment = finders_for_scope(environment_scope).first&.environment
- cluster = @clusters.find do |c|
- environment_scope == c.environment_scope
+ if environment.present? && environment.prometheus_adapter&.can_query?
+ func = ::Serverless::Function.new(project, name, environment.deployment_namespace)
+ environment.prometheus_adapter.query(:knative_invocation, func)
end
-
- func = ::Serverless::Function.new(project, name, cluster.kubernetes_namespace_for(project))
- prometheus_adapter.query(:knative_invocation, func)
end
def has_prometheus?(environment_scope)
- @clusters.any? do |cluster|
- environment_scope == cluster.environment_scope && cluster.application_prometheus_available?
+ finders_for_scope(environment_scope).any? do |finder|
+ finder.cluster.application_prometheus_available?
end
end
private
def knative_service(environment_scope, name)
- @clusters.map do |cluster|
- next if environment_scope != cluster.environment_scope
-
- services = cluster
- .knative_services_finder(project)
+ finders_for_scope(environment_scope).map do |finder|
+ services = finder
.services
.select { |svc| svc["metadata"]["name"] == name }
- add_metadata(cluster, services).first unless services.nil?
+ add_metadata(finder, services).first unless services.nil?
end
end
def knative_services
- @clusters.map do |cluster|
- services = cluster
- .knative_services_finder(project)
- .services
+ services_finders.map do |finder|
+ services = finder.services
- add_metadata(cluster, services) unless services.nil?
+ add_metadata(finder, services) unless services.nil?
end
end
- def add_metadata(cluster, services)
+ def add_metadata(finder, services)
+ add_pod_count = services.one?
+
services.each do |s|
- s["environment_scope"] = cluster.environment_scope
- s["cluster_id"] = cluster.id
+ s["environment_scope"] = finder.cluster.environment_scope
+ s["cluster_id"] = finder.cluster.id
- if services.length == 1
- s["podcount"] = cluster
- .knative_services_finder(project)
+ if add_pod_count
+ s["podcount"] = finder
.service_pod_details(s["metadata"]["name"])
.length
end
end
end
- # rubocop: disable CodeReuse/ServiceClass
- def prometheus_adapter
- @prometheus_adapter ||= ::Prometheus::AdapterService.new(project).prometheus_adapter
+ def services_finders
+ strong_memoize(:services_finders) do
+ available_environments.map(&:knative_services_finder).compact
+ end
+ end
+
+ def available_environments
+ @project.environments.available.preload_cluster
+ end
+
+ def finders_for_scope(environment_scope)
+ services_finders.select do |finder|
+ environment_scope == finder.cluster.environment_scope
+ end
end
- # rubocop: enable CodeReuse/ServiceClass
end
end
end
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index 5eb535cab58..08e52f32bb3 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -83,7 +83,7 @@ module Clusters
# ensures headers containing auth data are appended to original k8s client options
options = kube_client.rest_client.options.merge(headers: kube_client.headers)
- RestClient::Resource.new(proxy_url, options)
+ Gitlab::PrometheusClient.new(proxy_url, options)
rescue Kubeclient::HttpError
# If users have mistakenly set parameters or removed the depended clusters,
# `proxy_url` could raise an exception because gitlab can not communicate with the cluster.
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 8bb44b0ce40..97d39491b73 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -53,6 +53,7 @@ module Clusters
validates :name, cluster_name: true
validates :cluster_type, presence: true
validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true }
+ validates :namespace_per_environment, inclusion: { in: [true, false] }
validate :restrict_modification, on: :update
validate :no_groups, unless: :group_type?
@@ -100,16 +101,6 @@ module Clusters
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
- scope :with_knative_installed, -> { joins(:application_knative).merge(Clusters::Applications::Knative.available) }
-
- scope :preload_knative, -> {
- preload(
- :kubernetes_namespaces,
- :platform_kubernetes,
- :application_knative
- )
- }
-
def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc)
return [] if clusterable.is_a?(Instance)
@@ -177,36 +168,15 @@ module Clusters
platform_kubernetes.kubeclient if kubernetes?
end
- ##
- # This is subtly different to #find_or_initialize_kubernetes_namespace_for_project
- # below because it will ignore any namespaces that have not got a service account
- # token. This provides a guarantee that any namespace selected here can be used
- # for cluster operations - a namespace needs to have a service account configured
- # before it it can be used.
- #
- # This is used for selecting a namespace to use when querying a cluster, or
- # generating variables to pass to CI.
- def kubernetes_namespace_for(project)
- find_or_initialize_kubernetes_namespace_for_project(
- project, scope: kubernetes_namespaces.has_service_account_token
- ).namespace
- end
-
- ##
- # This is subtly different to #kubernetes_namespace_for because it will include
- # namespaces that have yet to receive a service account token. This allows
- # the namespace configuration process to be repeatable - if a namespace has
- # already been created without a token we don't need to create another
- # record entirely, just set the token on the pre-existing namespace.
- #
- # This is used for configuring cluster namespaces.
- def find_or_initialize_kubernetes_namespace_for_project(project, scope: kubernetes_namespaces)
- attributes = { project: project }
- attributes[:cluster_project] = cluster_project if project_type?
+ def kubernetes_namespace_for(environment)
+ project = environment.project
+ persisted_namespace = Clusters::KubernetesNamespaceFinder.new(
+ self,
+ project: project,
+ environment_slug: environment.slug
+ ).execute
- scope.find_or_initialize_by(attributes).tap do |namespace|
- namespace.set_defaults
- end
+ persisted_namespace&.namespace || Gitlab::Kubernetes::DefaultNamespace.new(self, project: project).from_environment_slug(environment.slug)
end
def allow_user_defined_namespace?
@@ -225,10 +195,6 @@ module Clusters
end
end
- def knative_services_finder(project)
- @knative_services_finder ||= KnativeServicesFinder.new(self, project)
- end
-
private
def instance_domain
diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb
index b0c4900546e..69a2b99fcb6 100644
--- a/app/models/clusters/kubernetes_namespace.rb
+++ b/app/models/clusters/kubernetes_namespace.rb
@@ -9,12 +9,12 @@ module Clusters
belongs_to :cluster_project, class_name: 'Clusters::Project'
belongs_to :cluster, class_name: 'Clusters::Cluster'
belongs_to :project, class_name: '::Project'
+ belongs_to :environment, optional: true
has_one :platform_kubernetes, through: :cluster
- before_validation :set_defaults
-
validates :namespace, presence: true
validates :namespace, uniqueness: { scope: :cluster_id }
+ validates :environment_id, uniqueness: { scope: [:cluster_id, :project_id] }, allow_nil: true
validates :service_account_name, presence: true
@@ -27,6 +27,7 @@ module Clusters
algorithm: 'aes-256-cbc'
scope :has_service_account_token, -> { where.not(encrypted_service_account_token: nil) }
+ scope :with_environment_slug, -> (slug) { joins(:environment).where(environments: { slug: slug }) }
def token_name
"#{namespace}-token"
@@ -42,34 +43,8 @@ module Clusters
end
end
- def set_defaults
- self.namespace ||= default_platform_kubernetes_namespace
- self.namespace ||= default_project_namespace
- self.service_account_name ||= default_service_account_name
- end
-
private
- def default_service_account_name
- return unless namespace
-
- "#{namespace}-service-account"
- end
-
- def default_platform_kubernetes_namespace
- platform_kubernetes&.namespace.presence
- end
-
- def default_project_namespace
- Gitlab::NamespaceSanitizer.sanitize(project_slug) if project_slug
- end
-
- def project_slug
- return unless project
-
- "#{project.path}-#{project.id}".downcase
- end
-
def kubeconfig
to_kubeconfig(
url: api_url,
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 9296c28776b..37614fbe3ca 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -51,11 +51,6 @@ module Clusters
delegate :provided_by_user?, to: :cluster, allow_nil: true
delegate :allow_user_defined_namespace?, to: :cluster, allow_nil: true
- # This is just to maintain compatibility with KubernetesService, which
- # will be removed in https://gitlab.com/gitlab-org/gitlab-ce/issues/39217.
- # It can be removed once KubernetesService is gone.
- delegate :kubernetes_namespace_for, to: :cluster, allow_nil: true
-
alias_method :active?, :enabled?
enum_with_nil authorization_type: {
@@ -66,7 +61,7 @@ module Clusters
default_value_for :authorization_type, :rbac
- def predefined_variables(project:)
+ def predefined_variables(project:, environment_name:)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'KUBE_URL', value: api_url)
@@ -77,15 +72,14 @@ module Clusters
end
if !cluster.managed?
- project_namespace = namespace.presence || "#{project.path}-#{project.id}".downcase
+ namespace = Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: project).from_environment_name(environment_name)
variables
- .append(key: 'KUBE_URL', value: api_url)
.append(key: 'KUBE_TOKEN', value: token, public: false, masked: true)
- .append(key: 'KUBE_NAMESPACE', value: project_namespace)
- .append(key: 'KUBECONFIG', value: kubeconfig(project_namespace), public: false, file: true)
+ .append(key: 'KUBE_NAMESPACE', value: namespace)
+ .append(key: 'KUBECONFIG', value: kubeconfig(namespace), public: false, file: true)
- elsif kubernetes_namespace = cluster.kubernetes_namespaces.has_service_account_token.find_by(project: project)
+ elsif kubernetes_namespace = find_persisted_namespace(project, environment_name: environment_name)
variables.concat(kubernetes_namespace.predefined_variables)
end
@@ -111,6 +105,22 @@ module Clusters
private
+ ##
+ # Environment slug can be predicted given an environment
+ # name, so even if the environment isn't persisted yet we
+ # still know what to look for.
+ def environment_slug(name)
+ Gitlab::Slug::Environment.new(name).generate
+ end
+
+ def find_persisted_namespace(project, environment_name:)
+ Clusters::KubernetesNamespaceFinder.new(
+ cluster,
+ project: project,
+ environment_slug: environment_slug(environment_name)
+ ).execute
+ end
+
def kubeconfig(namespace)
to_kubeconfig(
url: api_url,
diff --git a/app/models/concerns/prometheus_adapter.rb b/app/models/concerns/prometheus_adapter.rb
index c2542dbe743..9ac4722c6b1 100644
--- a/app/models/concerns/prometheus_adapter.rb
+++ b/app/models/concerns/prometheus_adapter.rb
@@ -14,10 +14,6 @@ module PrometheusAdapter
raise NotImplementedError
end
- def prometheus_client_wrapper
- Gitlab::PrometheusClient.new(prometheus_client)
- end
-
def can_query?
prometheus_client.present?
end
@@ -35,7 +31,7 @@ module PrometheusAdapter
def calculate_reactive_cache(query_class_name, *args)
return unless prometheus_client
- data = Object.const_get(query_class_name, false).new(prometheus_client_wrapper).query(*args)
+ data = Object.const_get(query_class_name, false).new(prometheus_client).query(*args)
{
success: true,
data: data,
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index db501b4b506..0bd90bd28e3 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -2,12 +2,14 @@
class DeployKey < Key
include IgnorableColumn
+ include FromUnion
has_many :deploy_keys_projects, inverse_of: :deploy_key, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :deploy_keys_projects
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
scope :are_public, -> { where(public: true) }
+ scope :with_projects, -> { includes(deploy_keys_projects: { project: [:route, :namespace] }) }
ignore_column :can_push
@@ -22,7 +24,7 @@ class DeployKey < Key
end
def almost_orphaned?
- self.deploy_keys_projects.length == 1
+ self.deploy_keys_projects.count == 1
end
def destroyed_when_orphaned?
@@ -46,6 +48,6 @@ class DeployKey < Key
end
def projects_with_write_access
- Project.preload(:route).where(id: deploy_keys_projects.with_write_access.select(:project_id))
+ Project.with_route.where(id: deploy_keys_projects.with_write_access.select(:project_id))
end
end
diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb
index 15906ed8e06..40c66d5bc4c 100644
--- a/app/models/deploy_keys_project.rb
+++ b/app/models/deploy_keys_project.rb
@@ -1,9 +1,8 @@
# frozen_string_literal: true
class DeployKeysProject < ApplicationRecord
- belongs_to :project
+ belongs_to :project, inverse_of: :deploy_keys_projects
belongs_to :deploy_key, inverse_of: :deploy_keys_projects
-
scope :without_project_deleted, -> { joins(:project).where(projects: { pending_delete: false }) }
scope :in_project, ->(project) { where(project: project) }
scope :with_write_access, -> { where(can_push: true) }
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 513427ac2c5..1b53c4b45f9 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -48,6 +48,7 @@ class Environment < ApplicationRecord
end
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
+ scope :preload_cluster, -> { preload(last_deployment: :cluster) }
##
# Search environments which have names like the given query.
@@ -170,7 +171,7 @@ class Environment < ApplicationRecord
def deployment_namespace
strong_memoize(:kubernetes_namespace) do
- deployment_platform&.kubernetes_namespace_for(project)
+ deployment_platform.cluster.kubernetes_namespace_for(self) if deployment_platform
end
end
@@ -233,6 +234,12 @@ class Environment < ApplicationRecord
end
end
+ def knative_services_finder
+ if last_deployment&.cluster
+ Clusters::KnativeServicesFinder.new(last_deployment.cluster, self)
+ end
+ end
+
private
def generate_slug
diff --git a/app/models/list.rb b/app/models/list.rb
index d28a9bda82d..ccadd39bda2 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -3,10 +3,11 @@
class List < ApplicationRecord
belongs_to :board
belongs_to :label
+ include Importable
enum list_type: { backlog: 0, label: 1, closed: 2, assignee: 3, milestone: 4 }
- validates :board, :list_type, presence: true
+ validates :board, :list_type, presence: true, unless: :importing?
validates :label, :position, presence: true, if: :label?
validates :label_id, uniqueness: { scope: :board_id }, if: :label?
validates :position, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :movable?
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index f45bd0e03de..2c9dbf2585c 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -196,6 +196,12 @@ class MergeRequestDiff < ApplicationRecord
real_size.presence || raw_diffs.size
end
+ def lines_count
+ strong_memoize(:lines_count) do
+ diffs.diff_files.sum(&:line_count)
+ end
+ end
+
def raw_diffs(options = {})
if options[:ignore_whitespace_change]
@diffs_no_whitespace ||= compare.diffs(options)
diff --git a/app/models/project.rb b/app/models/project.rb
index 8f234fba04f..960795b73cb 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -214,7 +214,7 @@ class Project < ApplicationRecord
as: :source, class_name: 'ProjectMember', dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :members_and_requesters, as: :source, class_name: 'ProjectMember'
- has_many :deploy_keys_projects
+ has_many :deploy_keys_projects, inverse_of: :project
has_many :deploy_keys, through: :deploy_keys_projects
has_many :users_star_projects
has_many :starrers, through: :users_star_projects, source: :user
@@ -1487,6 +1487,9 @@ class Project < ApplicationRecord
end
def pipeline_for(ref, sha = nil, id = nil)
+ sha ||= commit(ref).try(:sha)
+ return unless sha
+
if id.present?
pipelines_for(ref, sha).find_by(id: id)
else
@@ -1494,11 +1497,7 @@ class Project < ApplicationRecord
end
end
- def pipelines_for(ref, sha = nil)
- sha ||= commit(ref).try(:sha)
-
- return unless sha
-
+ def pipelines_for(ref, sha)
ci_pipelines.order(id: :desc).where(sha: sha, ref: ref)
end
@@ -1856,8 +1855,12 @@ class Project < ApplicationRecord
end
end
- def deployment_variables(environment: nil)
- deployment_platform(environment: environment)&.predefined_variables(project: self) || []
+ def deployment_variables(environment:)
+ platform = deployment_platform(environment: environment)
+
+ return [] unless platform.present?
+
+ platform.predefined_variables(project: self, environment_name: environment)
end
def auto_devops_variables
diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb
index 1103cb11e73..6f2b0f7747f 100644
--- a/app/models/project_services/mock_deployment_service.rb
+++ b/app/models/project_services/mock_deployment_service.rb
@@ -24,7 +24,7 @@ class MockDeploymentService < Service
%w()
end
- def predefined_variables(project:)
+ def predefined_variables(project:, environment_name:)
[]
end
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
index c68a9d923c8..6eff2ea2e3a 100644
--- a/app/models/project_services/prometheus_service.rb
+++ b/app/models/project_services/prometheus_service.rb
@@ -63,15 +63,16 @@ class PrometheusService < MonitoringService
# Check we can connect to the Prometheus API
def test(*args)
- Gitlab::PrometheusClient.new(prometheus_client).ping
-
+ prometheus_client.ping
{ success: true, result: 'Checked API endpoint' }
rescue Gitlab::PrometheusClient::Error => err
{ success: false, result: err }
end
def prometheus_client
- RestClient::Resource.new(api_url, max_redirects: 0) if should_return_client?
+ return unless should_return_client?
+
+ Gitlab::PrometheusClient.new(api_url)
end
def prometheus_available?
@@ -84,7 +85,7 @@ class PrometheusService < MonitoringService
private
def should_return_client?
- api_url && manual_configuration? && active? && valid?
+ api_url.present? && manual_configuration? && active? && valid?
end
def synchronize_service_state
diff --git a/app/models/user.rb b/app/models/user.rb
index b439d1c0c16..4630552e02e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -933,7 +933,7 @@ class User < ApplicationRecord
end
def project_deploy_keys
- DeployKey.unscoped.in_projects(authorized_projects.pluck(:id)).distinct(:id)
+ DeployKey.in_projects(authorized_projects.select(:id)).distinct(:id)
end
def highest_role
@@ -941,11 +941,10 @@ class User < ApplicationRecord
end
def accessible_deploy_keys
- @accessible_deploy_keys ||= begin
- key_ids = project_deploy_keys.pluck(:id)
- key_ids.push(*DeployKey.are_public.pluck(:id))
- DeployKey.where(id: key_ids)
- end
+ DeployKey.from_union([
+ DeployKey.where(id: project_deploy_keys.select(:deploy_key_id)),
+ DeployKey.are_public
+ ])
end
def created_by
diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb
index 2cf3278d240..f85c1a237a6 100644
--- a/app/presenters/blob_presenter.rb
+++ b/app/presenters/blob_presenter.rb
@@ -3,12 +3,13 @@
class BlobPresenter < Gitlab::View::Presenter::Delegated
presents :blob
- def highlight(plain: nil)
+ def highlight(since: nil, to: nil, plain: nil)
load_all_blob_data
Gitlab::Highlight.highlight(
blob.path,
- blob.data,
+ limited_blob_data(since: since, to: to),
+ since: since,
language: blob.language_from_gitattributes,
plain: plain
)
@@ -23,4 +24,18 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def load_all_blob_data
blob.load_all_data! if blob.respond_to?(:load_all_data!)
end
+
+ def limited_blob_data(since: nil, to: nil)
+ return blob.data if since.blank? || to.blank?
+
+ limited_blob_lines(since, to).join
+ end
+
+ def limited_blob_lines(since, to)
+ all_lines[since - 1..to - 1]
+ end
+
+ def all_lines
+ @all_lines ||= blob.data.lines
+ end
end
diff --git a/app/presenters/blobs/unfold_presenter.rb b/app/presenters/blobs/unfold_presenter.rb
index 21a1e1309e0..f4672d22fc9 100644
--- a/app/presenters/blobs/unfold_presenter.rb
+++ b/app/presenters/blobs/unfold_presenter.rb
@@ -21,20 +21,19 @@ module Blobs
load_all_blob_data
@subject = blob
- @all_lines = blob.data.lines
super(params)
if full?
- self.attributes = { since: 1, to: @all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 }
+ self.attributes = { since: 1, to: all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 }
end
end
# Returns an array of Gitlab::Diff::Line with match line added
def diff_lines
- diff_lines = lines.map.with_index do |line, index|
- full_line = limited_blob_lines[index].delete("\n")
+ diff_lines = limited_blob_lines(since, to).map.with_index do |line, index|
+ full_line = line.delete("\n")
- Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: line)
+ Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: lines[index])
end
add_match_line(diff_lines)
@@ -43,7 +42,7 @@ module Blobs
end
def lines
- @lines ||= limit(highlight.lines).map(&:html_safe)
+ @lines ||= highlight(since: since, to: to).lines.map(&:html_safe)
end
def match_line_text
@@ -59,7 +58,7 @@ module Blobs
def add_match_line(diff_lines)
return unless unfold?
- if bottom? && to < @all_lines.size
+ if bottom? && to < all_lines.size
old_pos = to - offset
new_pos = to
elsif since != 1
@@ -73,15 +72,5 @@ module Blobs
bottom? ? diff_lines.push(match_line) : diff_lines.unshift(match_line)
end
-
- def limited_blob_lines
- @limited_blob_lines ||= limit(@all_lines)
- end
-
- def limit(lines)
- return lines if full?
-
- lines[since - 1..to - 1]
- end
end
end
diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb
index 85518c9a3a4..6f8c4e1f902 100644
--- a/app/presenters/projects/settings/deploy_keys_presenter.rb
+++ b/app/presenters/projects/settings/deploy_keys_presenter.rb
@@ -12,48 +12,38 @@ module Projects
@key ||= DeployKey.new.tap { |dk| dk.deploy_keys_projects.build }
end
- # rubocop: disable CodeReuse/ActiveRecord
def enabled_keys
- @enabled_keys ||= project.deploy_keys.includes(:projects)
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def any_keys_enabled?
- enabled_keys.any?
+ project.deploy_keys
end
def available_keys
- @available_keys ||= current_user.accessible_deploy_keys - enabled_keys
+ current_user
+ .accessible_deploy_keys
+ .id_not_in(enabled_keys.select(:id))
+ .with_projects
end
- # rubocop: disable CodeReuse/ActiveRecord
def available_project_keys
- @available_project_keys ||= current_user.project_deploy_keys.includes(:projects) - enabled_keys
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def key_available?(deploy_key)
- available_keys.include?(deploy_key)
+ current_user
+ .project_deploy_keys
+ .id_not_in(enabled_keys.select(:id))
+ .with_projects
end
- # rubocop: disable CodeReuse/ActiveRecord
def available_public_keys
- return @available_public_keys if defined?(@available_public_keys)
-
- @available_public_keys ||= DeployKey.are_public.includes(:projects) - enabled_keys
-
- # Public keys that are already used by another accessible project are already
- # in @available_project_keys.
- @available_public_keys -= available_project_keys
+ DeployKey
+ .are_public
+ .id_not_in(enabled_keys.select(:id))
+ .id_not_in(available_project_keys.select(:id))
+ .with_projects
end
- # rubocop: enable CodeReuse/ActiveRecord
def as_json
serializer = DeployKeySerializer.new # rubocop: disable CodeReuse/Serializer
opts = { user: current_user }
{
- enabled_keys: serializer.represent(enabled_keys, opts),
+ enabled_keys: serializer.represent(enabled_keys.with_projects, opts),
available_project_keys: serializer.represent(available_project_keys, opts),
public_keys: serializer.represent(available_public_keys, opts)
}
diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb
index 54bf030aba1..e47d6454780 100644
--- a/app/serializers/deploy_key_entity.rb
+++ b/app/serializers/deploy_key_entity.rb
@@ -10,9 +10,10 @@ class DeployKeyEntity < Grape::Entity
expose :created_at
expose :updated_at
expose :deploy_keys_projects, using: DeployKeysProjectEntity do |deploy_key|
- deploy_key.deploy_keys_projects
- .without_project_deleted
- .select { |deploy_key_project| Ability.allowed?(options[:user], :read_project, deploy_key_project.project) }
+ deploy_key.deploy_keys_projects.select do |deploy_key_project|
+ !deploy_key_project.project&.pending_delete? &&
+ Ability.allowed?(options[:user], :read_project, deploy_key_project.project)
+ end
end
expose :can_edit
diff --git a/app/services/clusters/build_kubernetes_namespace_service.rb b/app/services/clusters/build_kubernetes_namespace_service.rb
new file mode 100644
index 00000000000..2574f77bbf9
--- /dev/null
+++ b/app/services/clusters/build_kubernetes_namespace_service.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Clusters
+ class BuildKubernetesNamespaceService
+ attr_reader :cluster, :environment
+
+ def initialize(cluster, environment:)
+ @cluster = cluster
+ @environment = environment
+ end
+
+ def execute
+ cluster.kubernetes_namespaces.build(attributes)
+ end
+
+ private
+
+ def attributes
+ attributes = {
+ project: environment.project,
+ namespace: namespace,
+ service_account_name: "#{namespace}-service-account"
+ }
+
+ attributes[:cluster_project] = cluster.cluster_project if cluster.project_type?
+ attributes[:environment] = environment if cluster.namespace_per_environment?
+
+ attributes
+ end
+
+ def namespace
+ Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: environment.project).from_environment_slug(environment.slug)
+ end
+ end
+end
diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb
index 5fb5e15c32d..e5a5b73321a 100644
--- a/app/services/clusters/create_service.rb
+++ b/app/services/clusters/create_service.rb
@@ -11,7 +11,8 @@ module Clusters
def execute(access_token: nil)
raise ArgumentError, 'Unknown clusterable provided' unless clusterable
- cluster_params = params.merge(user: current_user).merge(clusterable_params)
+ cluster_params = params.merge(global_params).merge(clusterable_params)
+
cluster_params[:provider_gcp_attributes].try do |provider|
provider[:access_token] = access_token
end
@@ -35,6 +36,10 @@ module Clusters
@clusterable ||= params.delete(:clusterable)
end
+ def global_params
+ { user: current_user, namespace_per_environment: Feature.enabled?(:kubernetes_namespace_per_environment, default_enabled: true) }
+ end
+
def clusterable_params
case clusterable
when ::Project
diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
index 806f320381d..c45dac7b273 100644
--- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
+++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
@@ -11,7 +11,6 @@ module Clusters
end
def execute
- configure_kubernetes_namespace
create_project_service_account
configure_kubernetes_token
@@ -22,10 +21,6 @@ module Clusters
attr_reader :cluster, :kubernetes_namespace, :platform
- def configure_kubernetes_namespace
- kubernetes_namespace.set_defaults
- end
-
def create_project_service_account
Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService.namespace_creator(
platform.kubeclient,
diff --git a/app/services/prometheus/proxy_service.rb b/app/services/prometheus/proxy_service.rb
index c5d2b84878b..a62eb76b8ce 100644
--- a/app/services/prometheus/proxy_service.rb
+++ b/app/services/prometheus/proxy_service.rb
@@ -98,7 +98,7 @@ module Prometheus
end
def prometheus_client_wrapper
- prometheus_adapter&.prometheus_client_wrapper
+ prometheus_adapter&.prometheus_client
end
def can_query?
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index cbe713b7468..ff0c5b241b2 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -32,6 +32,8 @@
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets qa-snippets-link' do
= _('Snippets')
+ = render_if_exists 'layouts/nav/sidebar/analytics_link'
+
- if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets])
%li.header-more.dropdown.d-xl-none{ class: ('d-lg-none' unless has_extra_nav_icons?) }
%a{ href: "#", data: { toggle: "dropdown" } }
@@ -53,6 +55,9 @@
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets' do
= _('Snippets')
+
+ = render_if_exists 'layouts/nav/sidebar/analytics_more_link'
+
%li.dropdown.d-lg-none
= render_if_exists 'dashboard/operations/nav_link_list'
- if can?(current_user, :read_instance_statistics)
diff --git a/app/views/projects/_export.html.haml b/app/views/projects/_export.html.haml
index 1056977886a..e42772c2dd9 100644
--- a/app/views/projects/_export.html.haml
+++ b/app/views/projects/_export.html.haml
@@ -15,6 +15,7 @@
%li= _('Project configuration, including services')
%li= _('Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities')
%li= _('LFS objects')
+ %li= _('Issue Boards')
%p= _('The following items will NOT be exported:')
%ul
%li= _('Job traces and artifacts')
diff --git a/app/workers/chaos/kill_worker.rb b/app/workers/chaos/kill_worker.rb
index bbad53c9b86..80f04db1be4 100644
--- a/app/workers/chaos/kill_worker.rb
+++ b/app/workers/chaos/kill_worker.rb
@@ -5,6 +5,8 @@ module Chaos
include ApplicationWorker
include ChaosQueue
+ sidekiq_options retry: false
+
def perform
Gitlab::Chaos.kill
end