Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo.yml1
-rw-r--r--app/assets/stylesheets/pages/settings.scss5
-rw-r--r--app/controllers/clusters/clusters_controller.rb2
-rw-r--r--app/helpers/services_helper.rb2
-rw-r--r--app/models/clusters/cluster.rb27
-rw-r--r--app/models/clusters/platforms/kubernetes.rb13
-rw-r--r--app/models/project_services/deployment_service.rb39
-rw-r--r--app/models/project_services/kubernetes_service.rb49
-rw-r--r--app/models/project_services/mock_deployment_service.rb16
-rw-r--r--app/models/service.rb4
-rw-r--r--app/views/admin/services/_deprecated_message.html.haml3
-rw-r--r--app/views/admin/services/_form.html.haml5
-rw-r--r--app/views/admin/services/edit.html.haml3
-rw-r--r--app/views/clusters/platforms/kubernetes/_form.html.haml2
-rw-r--r--app/views/projects/merge_requests/_mr_box.html.haml4
-rw-r--r--app/views/shared/projects/_search_form.html.haml2
-rw-r--r--changelogs/unreleased/55362-refresh-blank-service-account-token.yml5
-rw-r--r--changelogs/unreleased/56737-commits-and-mr-events-on-jira-api.yml5
-rw-r--r--changelogs/unreleased/60617-allow-switching-from-gitlab-managed-to-unmanaged-clusters.yml5
-rw-r--r--changelogs/unreleased/62685-add-index-invite-email-to-members.yml5
-rw-r--r--changelogs/unreleased/63079-exclude-k8s-namespaces-with-no-service-account-token.yml6
-rw-r--r--changelogs/unreleased/migrate_k8s_service_integration.yml5
-rw-r--r--changelogs/unreleased/readonly_k8s_integration.yml5
-rw-r--r--db/migrate/20190610142825_add_index_to_members_invite_email.rb21
-rw-r--r--db/post_migrate/20190517153211_migrate_k8s_service_integration.rb104
-rw-r--r--db/schema.rb1
-rw-r--r--doc/api/graphql/index.md2
-rw-r--r--doc/api/services.md51
-rw-r--r--doc/ci/merge_request_pipelines/index.md12
-rw-r--r--doc/ci/yaml/README.md18
-rw-r--r--doc/user/group/clusters/index.md4
-rw-r--r--doc/user/project/clusters/index.md4
-rw-r--r--doc/workflow/todos.md2
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb2
-rw-r--r--locale/gitlab.pot6
-rw-r--r--qa/qa/page/dashboard/projects.rb8
-rw-r--r--qa/qa/page/merge_request/show.rb8
-rw-r--r--qa/qa/resource/label.rb2
-rw-r--r--qa/qa/resource/project.rb6
-rw-r--r--qa/qa/resource/project_milestone.rb15
-rw-r--r--qa/qa/resource/sandbox.rb4
-rw-r--r--qa/qa/runtime/address.rb2
-rw-r--r--qa/qa/runtime/browser.rb19
-rw-r--r--qa/qa/runtime/env.rb23
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb80
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb59
-rw-r--r--qa/spec/runtime/env_spec.rb6
-rw-r--r--qa/spec/specs/runner_spec.rb68
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb4
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb4
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb22
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb4
-rw-r--r--spec/controllers/projects/services_controller_spec.rb26
-rw-r--r--spec/factories/clusters/kubernetes_namespaces.rb4
-rw-r--r--spec/factories/services.rb2
-rw-r--r--spec/features/projects/clusters/interchangeability_spec.rb16
-rw-r--r--spec/features/projects/environments/environment_spec.rb18
-rw-r--r--spec/features/projects/environments/environments_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb8
-rw-r--r--spec/migrations/migrate_k8s_service_integration_spec.rb161
-rw-r--r--spec/models/ci/pipeline_spec.rb37
-rw-r--r--spec/models/clusters/cluster_spec.rb91
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb56
-rw-r--r--spec/models/environment_spec.rb42
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb44
-rw-r--r--spec/models/project_spec.rb18
-rw-r--r--spec/models/service_spec.rb6
-rw-r--r--spec/requests/api/services_spec.rb27
-rw-r--r--spec/serializers/environment_entity_spec.rb10
-rw-r--r--spec/support/prometheus/additional_metrics_shared_examples.rb17
-rw-r--r--spec/support/shared_contexts/services_shared_context.rb3
-rw-r--r--spec/workers/reactive_caching_worker_spec.rb10
74 files changed, 925 insertions, 483 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 63b1685feda..698570efb07 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -799,7 +799,6 @@ Style/SelfAssignment:
Exclude:
- 'app/models/concerns/bulk_member_access_load.rb'
- 'app/serializers/base_serializer.rb'
- - 'spec/features/projects/clusters/interchangeability_spec.rb'
- 'spec/support/import_export/configuration_helper.rb'
# Offense count: 50
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 0a9c56f5625..3b62121eb0d 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -340,6 +340,11 @@
.deprecated-service {
cursor: default;
+
+ a {
+ font-weight: $gl-font-weight-bold;
+ color: $white-light;
+ }
}
.personal-access-tokens-never-expires-label {
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index 80ee7c35906..ec8077d18e3 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -128,6 +128,7 @@ class Clusters::ClustersController < Clusters::BaseController
:enabled,
:name,
:environment_scope,
+ :managed,
:base_domain,
platform_kubernetes_attributes: [
:api_url,
@@ -140,6 +141,7 @@ class Clusters::ClustersController < Clusters::BaseController
params.require(:cluster).permit(
:enabled,
:environment_scope,
+ :managed,
:base_domain,
platform_kubernetes_attributes: [
:namespace
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index d4b50b7ecfb..01ccf163b45 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -39,7 +39,7 @@ module ServicesHelper
end
def disable_fields_service?(service)
- !current_controller?("admin/services") && service.deprecated?
+ service.is_a?(KubernetesService) || (!current_controller?("admin/services") && service.deprecated?)
end
extend self
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index ccc877fb924..8c044c86c47 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -193,21 +193,40 @@ 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).namespace
+ find_or_initialize_kubernetes_namespace_for_project(
+ project, scope: kubernetes_namespaces.has_service_account_token
+ ).namespace
end
- def find_or_initialize_kubernetes_namespace_for_project(project)
+ ##
+ # 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?
- kubernetes_namespaces.find_or_initialize_by(attributes).tap do |namespace|
+ scope.find_or_initialize_by(attributes).tap do |namespace|
namespace.set_defaults
end
end
def allow_user_defined_namespace?
- project_type?
+ project_type? || !managed?
end
def kube_ingress_domain
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 8e06156c73d..272861cacf0 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -80,9 +80,18 @@ module Clusters
.append(key: 'KUBE_CA_PEM_FILE', value: ca_pem, file: true)
end
- if kubernetes_namespace = cluster.kubernetes_namespaces.has_service_account_token.find_by(project: project)
+ if !cluster.managed?
+ project_namespace = namespace.presence || "#{project.path}-#{project.id}".downcase
+
+ 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)
+
+ elsif kubernetes_namespace = cluster.kubernetes_namespaces.has_service_account_token.find_by(project: project)
variables.concat(kubernetes_namespace.predefined_variables)
- elsif cluster.project_type? || !cluster.managed?
+ elsif cluster.project_type?
# As of 11.11 a user can create a cluster that they manage themselves,
# which replicates the existing project-level cluster behaviour.
# Once we have marked all project-level clusters that make use of this
diff --git a/app/models/project_services/deployment_service.rb b/app/models/project_services/deployment_service.rb
deleted file mode 100644
index 80aa2101509..00000000000
--- a/app/models/project_services/deployment_service.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-# Base class for deployment services
-#
-# These services integrate with a deployment solution like Kubernetes/OpenShift,
-# Mesosphere, etc, to provide additional features to environments.
-class DeploymentService < Service
- default_value_for :category, 'deployment'
-
- def self.supported_events
- %w()
- end
-
- def predefined_variables(project:)
- []
- end
-
- # Environments may have a number of terminals. Should return an array of
- # hashes describing them, e.g.:
- #
- # [{
- # :selectors => {"a" => "b", "foo" => "bar"},
- # :url => "wss://external.example.com/exec",
- # :headers => {"Authorization" => "Token xxx"},
- # :subprotocols => ["foo"],
- # :ca_pem => "----BEGIN CERTIFICATE...", # optional
- # :created_at => Time.now.utc
- # }]
- #
- # Selectors should be a set of values that uniquely identify a particular
- # terminal
- def terminals(environment)
- raise NotImplementedError
- end
-
- def can_test?
- false
- end
-end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index aa6b4aa1d5e..edf7e886e77 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -5,10 +5,12 @@
# We'll move this class to Clusters::Platforms::Kubernetes, which contains exactly the same logic.
# After we've migrated data, we'll remove KubernetesService. This would happen in a few months.
# If you're modyfiyng this class, please note that you should update the same change in Clusters::Platforms::Kubernetes.
-class KubernetesService < DeploymentService
+class KubernetesService < Service
include Gitlab::Kubernetes
include ReactiveCaching
+ default_value_for :category, 'deployment'
+
self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
# Namespace defaults to the project path, but can be overridden in case that
@@ -32,7 +34,10 @@ class KubernetesService < DeploymentService
before_validation :enforce_namespace_to_lower_case
- validate :deprecation_validation, unless: :template?
+ attr_accessor :skip_deprecation_validation
+
+ validate :deprecation_validation, unless: :skip_deprecation_validation
+
validates :namespace,
allow_blank: true,
length: 1..63,
@@ -44,6 +49,14 @@ class KubernetesService < DeploymentService
after_save :clear_reactive_cache!
+ def self.supported_events
+ %w()
+ end
+
+ def can_test?
+ false
+ end
+
def initialize_properties
self.properties = {} if properties.nil?
end
@@ -56,11 +69,6 @@ class KubernetesService < DeploymentService
'Kubernetes / OpenShift integration'
end
- def help
- 'To enable terminal access to Kubernetes environments, label your ' \
- 'deployments with `app=$CI_ENVIRONMENT_SLUG`'
- end
-
def self.to_param
'kubernetes'
end
@@ -153,14 +161,25 @@ class KubernetesService < DeploymentService
end
def deprecated?
- !active
+ true
+ end
+
+ def editable?
+ false
end
def deprecation_message
- content = _("Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page") % {
- deprecated_message_content: deprecated_message_content,
- url: Gitlab::Routing.url_helpers.project_clusters_path(project)
- }
+ content = if project
+ _("Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page") % {
+ deprecated_message_content: deprecated_message_content,
+ url: Gitlab::Routing.url_helpers.project_clusters_path(project)
+ }
+ else
+ _("The instance-level Kubernetes service integration is deprecated. Your data has been migrated to an <a href=\"%{url}\"/>instance-level cluster</a>.") % {
+ url: Gitlab::Routing.url_helpers.admin_clusters_path
+ }
+ end
+
content.html_safe
end
@@ -243,10 +262,6 @@ class KubernetesService < DeploymentService
end
def deprecated_message_content
- if active?
- _("Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure")
- else
- _("Fields on this page are now uneditable, you can configure")
- end
+ _("Fields on this page are now uneditable, you can configure")
end
end
diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb
index 7ab1687f8ba..1103cb11e73 100644
--- a/app/models/project_services/mock_deployment_service.rb
+++ b/app/models/project_services/mock_deployment_service.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
-class MockDeploymentService < DeploymentService
+class MockDeploymentService < Service
+ default_value_for :category, 'deployment'
+
def title
'Mock deployment'
end
@@ -17,4 +19,16 @@ class MockDeploymentService < DeploymentService
def terminals(environment)
[]
end
+
+ def self.supported_events
+ %w()
+ end
+
+ def predefined_variables(project:)
+ []
+ end
+
+ def can_test?
+ false
+ end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 16fbe6648cc..40033003f3b 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -120,7 +120,7 @@ class Service < ApplicationRecord
end
def self.event_names
- self.supported_events.map { |event| "#{event}_events" }
+ self.supported_events.map { |event| ServicesHelper.service_event_field_name(event) }
end
def event_field(event)
@@ -152,7 +152,7 @@ class Service < ApplicationRecord
end
def self.supported_events
- %w(push tag_push issue confidential_issue merge_request wiki_page)
+ %w(commit push tag_push issue confidential_issue merge_request wiki_page)
end
def execute(data)
diff --git a/app/views/admin/services/_deprecated_message.html.haml b/app/views/admin/services/_deprecated_message.html.haml
new file mode 100644
index 00000000000..fea9506a4bb
--- /dev/null
+++ b/app/views/admin/services/_deprecated_message.html.haml
@@ -0,0 +1,3 @@
+.flash-container.flash-container-page
+ .flash-alert.deprecated-service
+ %span= @service.deprecation_message
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
index 1798b44bbb7..97373a3c350 100644
--- a/app/views/admin/services/_form.html.haml
+++ b/app/views/admin/services/_form.html.haml
@@ -6,5 +6,6 @@
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'fieldset-form' } do |form|
= render 'shared/service_settings', form: form, subject: @service
- .footer-block.row-content-block
- = form.submit 'Save', class: 'btn btn-success'
+ - unless @service.is_a?(KubernetesService)
+ .footer-block.row-content-block
+ = form.submit 'Save', class: 'btn btn-success'
diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml
index 512176649e6..79f5ab0d77d 100644
--- a/app/views/admin/services/edit.html.haml
+++ b/app/views/admin/services/edit.html.haml
@@ -1,4 +1,7 @@
- add_to_breadcrumbs "Service Templates", admin_application_settings_services_path
- breadcrumb_title @service.title
- page_title @service.title, "Service Templates"
+
+= render 'deprecated_message' if @service.deprecation_message
+
= render 'form'
diff --git a/app/views/clusters/platforms/kubernetes/_form.html.haml b/app/views/clusters/platforms/kubernetes/_form.html.haml
index c1727cf9079..f2e44462226 100644
--- a/app/views/clusters/platforms/kubernetes/_form.html.haml
+++ b/app/views/clusters/platforms/kubernetes/_form.html.haml
@@ -48,7 +48,7 @@
= s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.')
.form-group
- = field.check_box :managed, { disabled: true, label: s_('ClusterIntegration|GitLab-managed cluster'),
+ = field.check_box :managed, { label: s_('ClusterIntegration|GitLab-managed cluster'),
label_class: 'label-bold' }
.form-text.text-muted
= s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
diff --git a/app/views/projects/merge_requests/_mr_box.html.haml b/app/views/projects/merge_requests/_mr_box.html.haml
index 7f2c9dcacfd..4f09f47d795 100644
--- a/app/views/projects/merge_requests/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/_mr_box.html.haml
@@ -1,10 +1,10 @@
.detail-page-description
- %h2.title
+ %h2.title.qa-title
= markdown_field(@merge_request, :title)
%div
- if @merge_request.description.present?
- .description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' }
+ .description.qa-description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' }
.md
= markdown_field(@merge_request, :description)
%textarea.hidden.js-task-list-field
diff --git a/app/views/shared/projects/_search_form.html.haml b/app/views/shared/projects/_search_form.html.haml
index 7c7c0a363ac..4365e3f6877 100644
--- a/app/views/shared/projects/_search_form.html.haml
+++ b/app/views/shared/projects/_search_form.html.haml
@@ -1,7 +1,7 @@
- form_field_classes = local_assigns[:admin_view] || !Feature.enabled?(:project_list_filter_bar) ? 'input-short js-projects-list-filter' : ''
- placeholder = local_assigns[:search_form_placeholder] ? search_form_placeholder : 'Filter by name...'
-= form_tag filter_projects_path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
+= form_tag filter_projects_path, method: :get, class: 'project-filter-form qa-project-filter-form', id: 'project-filter-form' do |f|
= search_field_tag :name, params[:name],
placeholder: placeholder,
class: "project-filter-form-field form-control #{form_field_classes}",
diff --git a/changelogs/unreleased/55362-refresh-blank-service-account-token.yml b/changelogs/unreleased/55362-refresh-blank-service-account-token.yml
new file mode 100644
index 00000000000..3189de97e8b
--- /dev/null
+++ b/changelogs/unreleased/55362-refresh-blank-service-account-token.yml
@@ -0,0 +1,5 @@
+---
+title: Refresh service_account_token for kubernetes_namespaces
+merge_request: 29657
+author:
+type: fixed
diff --git a/changelogs/unreleased/56737-commits-and-mr-events-on-jira-api.yml b/changelogs/unreleased/56737-commits-and-mr-events-on-jira-api.yml
new file mode 100644
index 00000000000..ee2ce8acaeb
--- /dev/null
+++ b/changelogs/unreleased/56737-commits-and-mr-events-on-jira-api.yml
@@ -0,0 +1,5 @@
+---
+title: Expose all current events properly on services API
+merge_request: 29736
+author: Zsolt Kovari
+type: fixed
diff --git a/changelogs/unreleased/60617-allow-switching-from-gitlab-managed-to-unmanaged-clusters.yml b/changelogs/unreleased/60617-allow-switching-from-gitlab-managed-to-unmanaged-clusters.yml
new file mode 100644
index 00000000000..1127dde4fcf
--- /dev/null
+++ b/changelogs/unreleased/60617-allow-switching-from-gitlab-managed-to-unmanaged-clusters.yml
@@ -0,0 +1,5 @@
+---
+title: Allow switching clusters between managed and unmanaged
+merge_request: 29322
+author:
+type: added
diff --git a/changelogs/unreleased/62685-add-index-invite-email-to-members.yml b/changelogs/unreleased/62685-add-index-invite-email-to-members.yml
new file mode 100644
index 00000000000..80bb05e1709
--- /dev/null
+++ b/changelogs/unreleased/62685-add-index-invite-email-to-members.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on invite_email for members
+merge_request: 29768
+author:
+type: performance
diff --git a/changelogs/unreleased/63079-exclude-k8s-namespaces-with-no-service-account-token.yml b/changelogs/unreleased/63079-exclude-k8s-namespaces-with-no-service-account-token.yml
new file mode 100644
index 00000000000..9dc99c8a62f
--- /dev/null
+++ b/changelogs/unreleased/63079-exclude-k8s-namespaces-with-no-service-account-token.yml
@@ -0,0 +1,6 @@
+---
+title: Ensure a Kubernetes namespace is not used for deployments if there is no service
+ account token associated with it
+merge_request: 29643
+author:
+type: fixed
diff --git a/changelogs/unreleased/migrate_k8s_service_integration.yml b/changelogs/unreleased/migrate_k8s_service_integration.yml
new file mode 100644
index 00000000000..57f03e6bdab
--- /dev/null
+++ b/changelogs/unreleased/migrate_k8s_service_integration.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate Kubernetes service integration templates to clusters
+merge_request: 28534
+author:
+type: added
diff --git a/changelogs/unreleased/readonly_k8s_integration.yml b/changelogs/unreleased/readonly_k8s_integration.yml
new file mode 100644
index 00000000000..718705e8750
--- /dev/null
+++ b/changelogs/unreleased/readonly_k8s_integration.yml
@@ -0,0 +1,5 @@
+---
+title: Make Kubernetes service templates readonly
+merge_request: 29044
+author:
+type: removed
diff --git a/db/migrate/20190610142825_add_index_to_members_invite_email.rb b/db/migrate/20190610142825_add_index_to_members_invite_email.rb
new file mode 100644
index 00000000000..58157cc5313
--- /dev/null
+++ b/db/migrate/20190610142825_add_index_to_members_invite_email.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddIndexToMembersInviteEmail < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :members, [:invite_email]
+ end
+
+ def down
+ remove_concurrent_index :members, [:invite_email]
+ end
+end
diff --git a/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
new file mode 100644
index 00000000000..4bd04edb239
--- /dev/null
+++ b/db/post_migrate/20190517153211_migrate_k8s_service_integration.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+class MigrateK8sServiceIntegration < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ class Cluster < ActiveRecord::Base
+ self.table_name = 'clusters'
+
+ has_one :platform_kubernetes, class_name: 'MigrateK8sServiceIntegration::PlatformsKubernetes'
+
+ accepts_nested_attributes_for :platform_kubernetes
+
+ enum cluster_type: {
+ instance_type: 1,
+ group_type: 2,
+ project_type: 3
+ }
+
+ enum platform_type: {
+ kubernetes: 1
+ }
+
+ enum provider_type: {
+ user: 0,
+ gcp: 1
+ }
+ end
+
+ class PlatformsKubernetes < ActiveRecord::Base
+ self.table_name = 'cluster_platforms_kubernetes'
+
+ belongs_to :cluster, class_name: 'MigrateK8sServiceIntegration::Cluster'
+
+ attr_encrypted :token,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-cbc'
+ end
+
+ class Service < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'services'
+ self.inheritance_column = :_type_disabled # Disable STI, otherwise KubernetesModel will be looked up
+
+ belongs_to :project, class_name: 'MigrateK8sServiceIntegration::Project', foreign_key: :project_id
+
+ scope :kubernetes_service_templates, -> do
+ where(category: 'deployment', type: 'KubernetesService', template: true)
+ end
+
+ def api_url
+ parsed_properties['api_url'].presence
+ end
+
+ def ca_pem
+ parsed_properties['ca_pem']
+ end
+
+ def namespace
+ parsed_properties['namespace'].presence
+ end
+
+ def token
+ parsed_properties['token'].presence
+ end
+
+ private
+
+ def parsed_properties
+ @parsed_properties ||= JSON.parse(self.properties)
+ end
+ end
+
+ def up
+ has_instance_cluster = Cluster.instance_type.where(enabled: true).exists?
+
+ MigrateK8sServiceIntegration::Service.kubernetes_service_templates.find_each do |service|
+ next unless service.api_url && service.token
+
+ MigrateK8sServiceIntegration::Cluster.create!(
+ enabled: !has_instance_cluster && service.active,
+ managed: false,
+ name: 'KubernetesService',
+ cluster_type: 'instance_type',
+ provider_type: 'user',
+ platform_type: 'kubernetes',
+ platform_kubernetes_attributes: {
+ api_url: service.api_url,
+ ca_cert: service.ca_pem,
+ namespace: service.namespace,
+ token: service.token
+ }
+ )
+ end
+ end
+
+ def down
+ # It is not possible to tell which instance-level clusters were created by
+ # this migration. The original data is intentionally left intact.
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d1c13f44ab2..b003fdd5a9b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1850,6 +1850,7 @@ ActiveRecord::Schema.define(version: 20190613030606) do
t.boolean "ldap", default: false, null: false
t.boolean "override", default: false, null: false
t.index ["access_level"], name: "index_members_on_access_level", using: :btree
+ t.index ["invite_email"], name: "index_members_on_invite_email", using: :btree
t.index ["invite_token"], name: "index_members_on_invite_token", unique: true, using: :btree
t.index ["requested_at"], name: "index_members_on_requested_at", using: :btree
t.index ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 88e657a5d2f..6c1cce620ca 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -46,7 +46,7 @@ curl --data "value=100" --header "PRIVATE-TOKEN: <your_access_token>" https://gi
A first iteration of a GraphQL API includes the following queries
1. `project` : Within a project it is also possible to fetch a `mergeRequest` by IID.
-1. `group` : Only basic group information is currently supported.
+1. `group` : Basic group information and epics **[ULTIMATE]** are currently supported.
1. `namespace` : Within a namespace it is also possible to fetch `projects`.
### Multiplex queries
diff --git a/doc/api/services.md b/doc/api/services.md
index 898cfad7254..f38f96f64ad 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -22,6 +22,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `api_key` | string | true | User API token. User must have access to task, all comments will be attributed to this user. |
| `restrict_to_branch` | string | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Asana service
@@ -57,6 +58,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `token` | string | true | The authentication token
| `subdomain` | string | false | The subdomain setting |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Assembla service
@@ -96,6 +98,7 @@ Parameters:
| `build_key` | string | true | Bamboo build plan key like KEY |
| `username` | string | true | A user with API access, if applicable |
| `password` | string | true | Password of the user |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Atlassian Bamboo CI service
@@ -134,6 +137,7 @@ Parameters:
| `project_url` | string | true | Project url |
| `description` | string | false | Description |
| `title` | string | false | Title |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Bugzilla Service
@@ -170,6 +174,7 @@ Parameters:
| `token` | string | true | Buildkite project GitLab token |
| `project_url` | string | true | `https://buildkite.com/example/project` |
| `enable_ssl_verification` | boolean | false | Enable SSL verification |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Buildkite service
@@ -206,6 +211,7 @@ Parameters:
| `token` | string | true | Campfire token |
| `subdomain` | string | false | Campfire subdomain |
| `room` | string | false | Campfire room |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Campfire service
@@ -244,6 +250,7 @@ Parameters:
| `project_url` | string | true | Project url
| `description` | string | false | Description
| `title` | string | false | Title
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Custom Issue Tracker service
@@ -280,6 +287,10 @@ Parameters:
| `token` | string | true | Drone CI project specific token |
| `drone_url` | string | true | `http://drone.example.com` |
| `enable_ssl_verification` | boolean | false | Enable SSL verification |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
+
### Delete Drone CI service
@@ -316,6 +327,8 @@ Parameters:
| `recipients` | string | true | Emails separated by whitespace |
| `disable_diffs` | boolean | false | Disable code diffs |
| `send_from_committer_email` | boolean | false | Send from committer |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
### Delete Emails on push service
@@ -384,6 +397,7 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `token` | string | true | Flowdock Git source token |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Flowdock service
@@ -471,6 +485,14 @@ Parameters:
| `room` | string | false |Room name or ID |
| `api_version` | string | false | Leave blank for default (v2) |
| `server` | string | false | Leave blank for default. For example, `https://hipchat.example.com`. |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `issues_events` | boolean | false | Enable notifications for issue events |
+| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
+| `note_events` | boolean | false | Enable notifications for note events |
+| `confidental_note_events` | boolean | false | Enable notifications for confidential note events |
+| `pipeline_events` | boolean | false | Enable notifications for pipeline events |
### Delete HipChat service
@@ -511,6 +533,7 @@ Parameters:
| `server_host` | string | false | localhost |
| `server_port` | integer | false | 6659 |
| `colorize_messages` | boolean | false | Colorize messages |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Irker (IRC gateway) service
@@ -562,6 +585,8 @@ Parameters:
| `password` | string | yes | The password of the user created to be used with GitLab/JIRA. |
| `active` | boolean | no | Activates or deactivates the service. Defaults to false (deactivated). |
| `jira_issue_transition_id` | string | no | The ID of a transition that moves issues to a closed state. You can find this number under the JIRA workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. |
+| `commit_events` | boolean | false | Enable notifications for commit events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
### Delete JIRA service
@@ -715,9 +740,14 @@ PUT /projects/:id/services/packagist
Parameters:
-- `username` (**required**)
-- `token` (**required**)
-- `server` (optional)
+| Parameter | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `username` | string | yes | The username of a Packagist account |
+| `token` | string | yes | API token to the Packagist server |
+| `server` | boolean | no | URL of the Packagist server. Leave blank for default: https://packagist.org |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
### Delete Packagist service
@@ -755,6 +785,7 @@ Parameters:
| `add_pusher` | boolean | no | Add pusher to recipients list |
| `notify_only_broken_pipelines` | boolean | no | Notify only broken pipelines |
| `notify_only_default_branch` | boolean | no | Send notifications only for the default branch ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/28271)) |
+| `pipeline_events` | boolean | false | Enable notifications for pipeline events |
### Delete Pipeline-Emails service
@@ -790,6 +821,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `token` | string | true | The PivotalTracker token |
| `restrict_to_branch` | boolean | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete PivotalTracker service
@@ -862,6 +894,7 @@ Parameters:
| `priority` | string | true | The priority |
| `device` | string | false | Leave blank for all active devices |
| `sound` | string | false | The sound of the notification |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Pushover service
@@ -899,6 +932,7 @@ Parameters:
| `project_url` | string | true | Project url |
| `issues_url` | string | true | Issue url |
| `description` | string | false | Description |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete Redmine service
@@ -989,6 +1023,15 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `webhook` | string | true | The Microsoft Teams webhook. For example, `https://outlook.office.com/webhook/...` |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `issues_events` | boolean | false | Enable notifications for issue events |
+| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
+| `note_events` | boolean | false | Enable notifications for note events |
+| `confidental_note_events` | boolean | false | Enable notifications for confidential note events |
+| `pipeline_events` | boolean | false | Enable notifications for pipeline events |
+| `wiki_page_events` | boolean | false | Enable notifications for wiki page events |
### Delete Microsoft Teams service
@@ -1084,6 +1127,7 @@ Parameters:
| `build_type` | string | true | Build configuration ID |
| `username` | string | true | A user with permissions to trigger a manual build |
| `password` | string | true | The password of the user |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete JetBrains TeamCity CI service
@@ -1230,6 +1274,7 @@ Parameters:
| `issues_url` | string | true | Issue url |
| `project_url` | string | true | Project url |
| `description` | string | false | Description |
+| `push_events` | boolean | false | Enable notifications for push events |
### Delete YouTrack Service
diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md
index d8c1cefc8df..5adb7ebd30d 100644
--- a/doc/ci/merge_request_pipelines/index.md
+++ b/doc/ci/merge_request_pipelines/index.md
@@ -124,7 +124,7 @@ otherwise pipelines for merged results won't run and your merge requests will be
## Merge Trains **[PREMIUM]**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9186) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.0.
-> This feature is disabled by default until we resolve issues with [contention handling](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222), but [can be enabled manually](#enabling-merge-trains).
+> This feature is disabled by default, but [can be enabled manually](#enabling-merge-trains).
[Pipelines for merged results](#pipelines-for-merged-results-premium) introduces
running a build on the result of the merged code prior to merging, as a way to keep master green.
@@ -142,9 +142,8 @@ If the button is subsequently pressed in a different MR, instead of creating a n
it creates a new pipeline targeting the merge result of the previous MR plus the target branch.
Pipelines invalidated through failures are immediately canceled and requeued.
-CAUTION: **Warning:**
-At this moment, each merge train can generate a merge ref and run a pipeline **one at a time** due to a technical challenge.
-We have [an issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222) to tackle this problem to make the pipelines for merged results run in parallel.
+CAUTION: **Caution:**
+At the moment, each merge train can generate a merge ref and run a pipeline **one at a time**. We plan to make the pipelines for merged results [run in parallel](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222) in a future release.
### Enabling Merge Trains
@@ -186,11 +185,6 @@ button while the latest pipeline is running.
![Add to merge train when pipeline succeeds](img/merge_train_start_when_pipeline_succeeds.png)
-### Merge Train's limitations
-
-- At this moment, each merge train can generate a merge ref and run a pipeline **one at a time** due to a technical challenge.
- We have [an issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222) to tackle this problem to make the pipelines for merged results run in parallel.
-
## Excluding certain jobs
The behavior of the `only: merge_requests` parameter is such that _only_ jobs with
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 4c170056a49..2759f1c5160 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -2620,6 +2620,24 @@ test:
- pwd
```
+### Nested paths
+
+The value of `GIT_CLONE_PATH` is expanded once and nesting variables
+within it is not supported.
+
+For example, you define both the variables below in your
+`.gitlab-ci.yml` file:
+
+```yml
+variables:
+ GOPATH: $CI_BUILDS_DIR/go
+ GIT_CLONE_PATH: $GOPATH/src/namespace/project
+```
+
+The value of `GIT_CLONE_PATH` is expanded once into
+`$CI_BUILDS_DIR/go/src/namespace/project`, and results in failure
+because `$CI_BUILDS_DIR` is not expanded.
+
## Special YAML features
It's possible to use special YAML features like anchors (`&`), aliases (`*`)
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 3c5e820c1ca..26d764fa2cf 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -57,10 +57,6 @@ differentiate the new cluster from the rest.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011) in GitLab 11.5.
> Became [optional](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26565) in GitLab 11.11.
-NOTE: **Note:**
-Only available when creating clusters. Existing clusters not managed by GitLab
-cannot become GitLab-managed later.
-
You can choose to allow GitLab to manage your cluster for you. If your cluster is
managed by GitLab, resources for your projects will be automatically created. See the
[Access controls](../../project/clusters/index.md#access-controls) section for details on which resources will
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index dc21db603d6..181b20dc710 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -225,10 +225,6 @@ applications running on the cluster.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011) in GitLab 11.5.
> Became [optional](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26565) in GitLab 11.11.
-NOTE: **Note:**
-Only available when creating clusters. Existing clusters not managed by GitLab
-cannot become GitLab-managed later.
-
You can choose to allow GitLab to manage your cluster for you. If your cluster is
managed by GitLab, resources for your projects will be automatically created. See the
[Access controls](#access-controls) section for details on which resources will
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
index 32907db4f46..3eac79427cf 100644
--- a/doc/workflow/todos.md
+++ b/doc/workflow/todos.md
@@ -34,6 +34,8 @@ A Todo appears in your Todos dashboard when:
- the author, or
- have set it to automatically merge once pipeline succeeds.
+Todo triggers are not affected by [GitLab Notification Email settings](notifications.md).
+
NOTE: **Note:**
When an user no longer has access to a resource related to a Todo like an issue, merge request, project or group the related Todos, for security reasons, gets deleted within the next hour. The delete is delayed to prevent data loss in case user got their access revoked by mistake.
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 8840accf675..25e9fdd5fce 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -997,7 +997,7 @@ module API
class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active
- expose :push_events, :issues_events, :confidential_issues_events
+ expose :commit_events, :push_events, :issues_events, :confidential_issues_events
expose :merge_requests_events, :tag_push_events, :note_events
expose :confidential_note_events, :pipeline_events, :wiki_page_events
expose :job_events
diff --git a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
index dbdc59505ac..531c9ce4256 100644
--- a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
+++ b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb
@@ -9,7 +9,7 @@ module Gitlab
deployment_cluster.present? &&
deployment_cluster.managed? &&
!deployment_cluster.project_type? &&
- kubernetes_namespace.new_record?
+ (kubernetes_namespace.new_record? || kubernetes_namespace.service_account_token.blank?)
end
def complete!
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 186c4cb2dba..0cabaeabb9a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -9999,6 +9999,9 @@ msgstr ""
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
+msgid "The instance-level Kubernetes service integration is deprecated. Your data has been migrated to an <a href=\"%{url}\"/>instance-level cluster</a>."
+msgstr ""
+
msgid "The invitation could not be accepted."
msgstr ""
@@ -11943,9 +11946,6 @@ msgstr ""
msgid "Your Groups"
msgstr ""
-msgid "Your Kubernetes cluster information on this page is still editable, but you are advised to disable and reconfigure"
-msgstr ""
-
msgid "Your Primary Email will be used for avatar detection."
msgstr ""
diff --git a/qa/qa/page/dashboard/projects.rb b/qa/qa/page/dashboard/projects.rb
index 7ab8ee39f72..0c23d7cffbb 100644
--- a/qa/qa/page/dashboard/projects.rb
+++ b/qa/qa/page/dashboard/projects.rb
@@ -5,7 +5,7 @@ module QA
module Dashboard
class Projects < Page::Base
view 'app/views/shared/projects/_search_form.html.haml' do
- element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/ # rubocop:disable QA/ElementWithPattern
+ element :project_filter_form, required: true
end
def go_to_project(name)
@@ -14,10 +14,14 @@ module QA
find_link(text: name).click
end
+ def self.path
+ '/'
+ end
+
private
def filter_by_name(name)
- page.within('form#project-filter-form') do
+ within_element(:project_filter_form) do
fill_in :name, with: name
end
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 5aef868a805..6a415b56e50 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -111,6 +111,14 @@ module QA
end
end
+ def has_title?(title)
+ has_element?(:title, text: title)
+ end
+
+ def has_description?(description)
+ has_element?(:description, text: description)
+ end
+
def merge!
# The merge button is disabled on load
wait do
diff --git a/qa/qa/resource/label.rb b/qa/qa/resource/label.rb
index 5a681a5fe9f..3750725c440 100644
--- a/qa/qa/resource/label.rb
+++ b/qa/qa/resource/label.rb
@@ -46,7 +46,7 @@ module QA
end
def api_post_path
- "/projects/#{project}/labels"
+ "/projects/#{project.id}/labels"
end
def api_post_body
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index d706439a891..e8ea947581a 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -18,7 +18,11 @@ module QA
end
attribute :path_with_namespace do
- "#{group.sandbox.path}/#{group.path}/#{name}" if group
+ "#{sandbox_path}#{group.path}/#{name}" if group
+ end
+
+ def sandbox_path
+ group.respond_to?('sandbox') ? "#{group.sandbox.path}/" : ''
end
attribute :repository_ssh_location do
diff --git a/qa/qa/resource/project_milestone.rb b/qa/qa/resource/project_milestone.rb
index 8ace75f695a..70640eac095 100644
--- a/qa/qa/resource/project_milestone.rb
+++ b/qa/qa/resource/project_milestone.rb
@@ -31,6 +31,21 @@ module QA
milestone_new.click_milestone_create_button
end
end
+
+ def api_get_path
+ "/projects/#{project.id}/milestones/#{id}"
+ end
+
+ def api_post_path
+ "/projects/#{project.id}/milestones"
+ end
+
+ def api_post_body
+ {
+ description: @description,
+ title: @title
+ }
+ end
end
end
end
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 942eea5cc40..e2b1c4c0831 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -44,6 +44,10 @@ module QA
"/groups/#{path}"
end
+ def api_members_path
+ "#{api_get_path}/members"
+ end
+
def api_post_path
'/groups'
end
diff --git a/qa/qa/runtime/address.rb b/qa/qa/runtime/address.rb
index 98d042fb43a..c622051bb6d 100644
--- a/qa/qa/runtime/address.rb
+++ b/qa/qa/runtime/address.rb
@@ -5,7 +5,7 @@ module QA
class Address
attr_reader :address
- def initialize(instance, page = nil)
+ def initialize(instance, page)
@instance = instance
@address = host + (page.is_a?(String) ? page : page&.path)
end
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 3bf4b3bbbfb..ed0779b93cc 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'rspec/core'
+require 'rspec/expectations'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'selenium-webdriver'
@@ -27,13 +28,12 @@ module QA
# In case of an address that is a symbol we will try to guess address
# based on `Runtime::Scenario#something_address`.
#
- def visit(address, page = nil, &block)
- Browser::Session.new(address, page).perform(&block)
+ def visit(address, page_class, &block)
+ Browser::Session.new(address, page_class).perform(&block)
end
- def self.visit(address, page = nil, &block)
- new.visit(address, page, &block)
- page.validate_elements_present!
+ def self.visit(address, page_class, &block)
+ new.visit(address, page_class, &block)
end
def self.configure!
@@ -128,8 +128,11 @@ module QA
class Session
include Capybara::DSL
- def initialize(instance, page = nil)
- @session_address = Runtime::Address.new(instance, page)
+ attr_reader :page_class
+
+ def initialize(instance, page_class)
+ @session_address = Runtime::Address.new(instance, page_class)
+ @page_class = page_class
end
def url
@@ -139,6 +142,8 @@ module QA
def perform(&block)
visit(url)
+ page_class.validate_elements_present!
+
if QA::Runtime::Env.qa_cookies
browser = Capybara.current_session.driver.browser
QA::Runtime::Env.qa_cookies.each do |cookie|
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 82510dfa03c..96f337dc081 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -10,13 +10,26 @@ module QA
# The environment variables used to indicate if the environment under test
# supports the given feature
SUPPORTED_FEATURES = {
- git_protocol_v2: 'QA_CAN_TEST_GIT_PROTOCOL_V2'
+ git_protocol_v2: 'QA_CAN_TEST_GIT_PROTOCOL_V2',
+ admin: 'QA_CAN_TEST_ADMIN_FEATURES'
}.freeze
def supported_features
SUPPORTED_FEATURES
end
+ def admin_password
+ ENV['GITLAB_ADMIN_PASSWORD']
+ end
+
+ def admin_username
+ ENV['GITLAB_ADMIN_USERNAME']
+ end
+
+ def admin_personal_access_token
+ ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
+ end
+
def debug?
enabled?(ENV['QA_DEBUG'], default: false)
end
@@ -92,14 +105,6 @@ module QA
ENV['GITLAB_PASSWORD']
end
- def admin_username
- ENV['GITLAB_ADMIN_USERNAME']
- end
-
- def admin_password
- ENV['GITLAB_ADMIN_PASSWORD']
- end
-
def github_username
ENV['GITHUB_USERNAME']
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
index cd1c7545944..6969f123f95 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -1,74 +1,64 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/50
- context 'Create', :quarantine do
- describe 'Merge request creation' do
- it 'user creates a new merge request', :smoke do
+ context 'Create' do
+ describe 'Create a new merge request' do
+ before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
- current_project = Resource::Project.fabricate! do |project|
- project.name = 'project-with-merge-request'
+ @project = Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project'
end
- merge_request_title = 'This is a merge request'
- merge_request_description = 'Great feature'
+ @merge_request_title = 'One merge request to rule them all'
+ @merge_request_description = '... to find them, to bring them all, and in the darkness bind them'
+ end
- Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.title = merge_request_title
- merge_request.description = merge_request_description
- merge_request.project = current_project
+ it 'creates a basic merge request', :smoke do
+ Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
+ merge_request.project = @project
+ merge_request.title = @merge_request_title
+ merge_request.description = @merge_request_description
end
- expect(page).to have_content(merge_request_title)
- expect(page).to have_content(merge_request_description)
- expect(page).to have_content('Opened just now')
+ Page::MergeRequest::Show.perform do |merge_request|
+ expect(merge_request).to have_title(@merge_request_title)
+ expect(merge_request).to have_description(@merge_request_description)
+ end
end
- it 'user creates a new merge request with a milestone and label' do
+ it 'creates a merge request with a milestone and label' do
gitlab_account_username = "@#{Runtime::User.username}"
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.act { sign_in_using_credentials }
-
- current_project = Resource::Project.fabricate! do |project|
- project.name = 'project-with-merge-request-and-milestone'
- end
-
- current_milestone = Resource::ProjectMilestone.fabricate! do |milestone|
- milestone.title = 'unique-milestone'
- milestone.project = current_project
+ milestone = Resource::ProjectMilestone.fabricate_via_api! do |milestone|
+ milestone.project = @project
+ milestone.title = 'milestone'
end
- new_label = Resource::Label.fabricate_via_browser_ui! do |label|
- label.project = current_project
- label.title = 'qa-mr-test-label'
- label.description = 'Merge Request label'
+ label = Resource::Label.fabricate_via_api! do |label|
+ label.project = @project
+ label.title = 'label'
end
- merge_request_title = 'This is a merge request with a milestone and a label'
- merge_request_description = 'Great feature with milestone'
-
- Resource::MergeRequest.fabricate! do |merge_request|
- merge_request.title = merge_request_title
- merge_request.description = merge_request_description
- merge_request.project = current_project
- merge_request.milestone = current_milestone
+ Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
+ merge_request.title = @merge_request_title
+ merge_request.description = @merge_request_description
+ merge_request.project = @project
+ merge_request.milestone = milestone
merge_request.assignee = 'me'
- merge_request.labels.push(new_label)
+ merge_request.labels.push(label)
end
Page::MergeRequest::Show.perform do |merge_request|
- expect(merge_request).to have_content(merge_request_title)
- expect(merge_request).to have_content(merge_request_description)
- expect(merge_request).to have_content('Opened just now')
+ expect(merge_request).to have_title(@merge_request_title)
+ expect(merge_request).to have_description(@merge_request_description)
expect(merge_request).to have_assignee(gitlab_account_username)
- expect(merge_request).to have_label(new_label.title)
+ expect(merge_request).to have_label(label.title)
end
Page::Issuable::Sidebar.perform do |sidebar|
- expect(sidebar).to have_milestone(current_milestone.title)
+ expect(sidebar).to have_milestone(milestone.title)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 5bfafdfa041..247cde38e52 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -1,74 +1,57 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/37
- context 'Create', :quarantine do
+ context 'Create', :requires_admin do
describe 'push after setting the file size limit via admin/application_settings' do
- before(:all) do
- push = Resource::Repository::ProjectPush.fabricate! do |p|
- p.file_name = 'README.md'
- p.file_content = '# This is a test project'
- p.commit_message = 'Add README.md'
+ before(:context) do
+ @project = Resource::Project.fabricate_via_api! do |p|
+ p.name = 'project-test-push-limit'
+ p.initialize_with_readme = true
end
- @project = push.project
+ @api_client = Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
end
- before do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.perform(&:sign_in_using_credentials)
- end
-
- after(:all) do
+ after(:context) do
# need to set the default value after test
# default value for file size limit is empty
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.perform(&:sign_in_using_credentials)
-
- set_file_size_limit('')
-
- Page::Main::Menu.perform(&:sign_out)
+ set_file_size_limit(nil)
end
it 'push successful when the file size is under the limit' do
set_file_size_limit(5)
- expect(page).to have_content("Application settings saved successfully")
-
push = push_new_file('oversize_file_1.bin', wait_for_push: true)
expect(push.output).not_to have_content 'remote: fatal: pack exceeds maximum allowed size'
end
it 'push fails when the file size is above the limit' do
set_file_size_limit(1)
- expect(page).to have_content("Application settings saved successfully")
-
expect { push_new_file('oversize_file_2.bin', wait_for_push: false) }
.to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: fatal: pack exceeds maximum allowed size/)
end
def set_file_size_limit(limit)
- Page::Main::Menu.perform(&:click_admin_area)
- Page::Admin::Menu.perform(&:go_to_general_settings)
+ request = Runtime::API::Request.new(@api_client, '/application/settings')
+ put request.url, receive_max_input_size: limit
- Page::Admin::Settings::General.perform do |setting|
- setting.expand_account_and_limit do |page|
- page.set_max_file_size(limit)
- page.save_settings
- end
- end
+ expect_status(200)
+ expect(json_body).to match(
+ a_hash_including(receive_max_input_size: limit)
+ )
end
def push_new_file(file_name, wait_for_push: true)
- @project.visit!
-
- Resource::Repository::ProjectPush.fabricate! do |p|
- p.project = @project
+ commit_message = 'Adding a new file'
+ output = Resource::Repository::Push.fabricate! do |p|
+ p.repository_http_uri = @project.repository_http_location.uri
p.file_name = file_name
p.file_content = SecureRandom.random_bytes(2000000)
- p.commit_message = 'Adding a new file'
- p.wait_for_push = wait_for_push
+ p.commit_message = commit_message
p.new_branch = false
end
+ @project.wait_for_push commit_message
+
+ output
end
end
end
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index 2560695ef2e..caf96a213e1 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -227,6 +227,12 @@ describe QA::Runtime::Env do
env_key: 'QA_CAN_TEST_GIT_PROTOCOL_V2',
default: true
+ it_behaves_like 'boolean method with parameter',
+ method: :can_test?,
+ param: :admin,
+ env_key: 'QA_CAN_TEST_ADMIN_FEATURES',
+ default: true
+
it 'raises ArgumentError if feature is unknown' do
expect { described_class.can_test? :foo }.to raise_error(ArgumentError, 'Unknown feature "foo"')
end
diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb
index 5c86c102105..f94145d148e 100644
--- a/qa/spec/specs/runner_spec.rb
+++ b/qa/spec/specs/runner_spec.rb
@@ -1,16 +1,22 @@
# frozen_string_literal: true
+require 'active_support/core_ext/hash'
+
describe QA::Specs::Runner do
+ shared_examples 'excludes orchestrated' do
+ it 'excludes the orchestrated tag and includes default args' do
+ expect_rspec_runner_arguments(['--tag', '~orchestrated', *described_class::DEFAULT_TEST_PATH_ARGS])
+
+ subject.perform
+ end
+ end
+
context '#perform' do
before do
allow(QA::Runtime::Browser).to receive(:configure!)
end
- it 'excludes the orchestrated tag by default' do
- expect_rspec_runner_arguments(['--tag', '~orchestrated', *described_class::DEFAULT_TEST_PATH_ARGS])
-
- subject.perform
- end
+ it_behaves_like 'excludes orchestrated'
context 'when tty is set' do
subject { described_class.new.tap { |runner| runner.tty = true } }
@@ -67,8 +73,6 @@ describe QA::Specs::Runner do
allow(QA::Runtime::Env).to receive(:signup_disabled?).and_return(true)
end
- subject { described_class.new }
-
it 'includes default args and excludes the skip_signup_disabled tag' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~skip_signup_disabled', *described_class::DEFAULT_TEST_PATH_ARGS])
@@ -76,18 +80,54 @@ describe QA::Specs::Runner do
end
end
- context 'when git protocol v2 is not supported' do
- before do
- allow(QA::Runtime::Env).to receive(:can_test?).with(:git_protocol_v2).and_return(false)
+ context 'testable features' do
+ shared_examples 'one supported feature' do |feature|
+ before do
+ QA::Runtime::Env.supported_features.each do |tag, _|
+ allow(QA::Runtime::Env).to receive(:can_test?).with(tag).and_return(false)
+ end
+
+ allow(QA::Runtime::Env).to receive(:can_test?).with(feature).and_return(true) unless feature.nil?
+ end
+
+ it 'includes default args and excludes all unsupported tags' do
+ expect_rspec_runner_arguments(['--tag', '~orchestrated', *excluded_feature_tags_except(feature), *described_class::DEFAULT_TEST_PATH_ARGS])
+
+ subject.perform
+ end
end
- subject { described_class.new }
+ context 'when only git protocol 2 is supported' do
+ it_behaves_like 'one supported feature', :git_protocol_v2
+ end
- it 'includes default args and excludes the requires_git_protocol_v2 tag' do
- expect_rspec_runner_arguments(['--tag', '~orchestrated', '--tag', '~requires_git_protocol_v2', *described_class::DEFAULT_TEST_PATH_ARGS])
+ context 'when only admin features are supported' do
+ it_behaves_like 'one supported feature', :admin
+ end
- subject.perform
+ context 'when no features are supported' do
+ it_behaves_like 'one supported feature', nil
end
+
+ context 'when all features are supported' do
+ before do
+ QA::Runtime::Env.supported_features.each do |tag, _|
+ allow(QA::Runtime::Env).to receive(:can_test?).with(tag).and_return(true)
+ end
+ end
+
+ it_behaves_like 'excludes orchestrated'
+ end
+
+ context 'when features are not specified' do
+ it_behaves_like 'excludes orchestrated'
+ end
+ end
+
+ def excluded_feature_tags_except(tag)
+ QA::Runtime::Env.supported_features.except(tag).map do |tag, _|
+ ['--tag', "~requires_#{tag}"]
+ end.flatten
end
def expect_rspec_runner_arguments(arguments)
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index 7b77cb186a4..7709f525119 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -396,6 +396,7 @@ describe Admin::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
base_domain: domain
}
}
@@ -409,6 +410,7 @@ describe Admin::ClustersController do
expect(flash[:notice]).to eq('Kubernetes cluster was successfully updated.')
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
expect(cluster.domain).to eq('test-domain.com')
end
@@ -433,6 +435,7 @@ describe Admin::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
domain: domain
}
}
@@ -445,6 +448,7 @@ describe Admin::ClustersController do
expect(response).to have_http_status(:no_content)
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
end
end
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 7349cb7094c..2f64c7f3460 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -463,6 +463,7 @@ describe Groups::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
base_domain: domain
}
}
@@ -476,6 +477,7 @@ describe Groups::ClustersController do
expect(flash[:notice]).to eq('Kubernetes cluster was successfully updated.')
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
expect(cluster.domain).to eq('test-domain.com')
end
@@ -500,6 +502,7 @@ describe Groups::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
domain: domain
}
}
@@ -512,6 +515,7 @@ describe Groups::ClustersController do
expect(response).to have_http_status(:no_content)
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
end
end
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index c778b7888dc..cf201c9f735 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -123,7 +123,11 @@ describe Projects::BranchesController do
expect(response).to redirect_to project_tree_path(project, branch)
end
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ before do
+ create(:cluster, :provided_by_gcp, projects: [project])
+ end
+
it 'redirects to autodeploy setup page' do
result = { status: :success, branch: double(name: branch) }
@@ -143,22 +147,6 @@ describe Projects::BranchesController do
end
end
- context 'when user configured kubernetes from Integration > Kubernetes' do
- before do
- project.services << build(:kubernetes_service)
- end
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- before do
- create(:cluster, :provided_by_gcp, projects: [project])
- end
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
it 'redirects to autodeploy setup page' do
result = { status: :success, branch: double(name: branch) }
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 8d37bd82d21..fa49438287f 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -449,6 +449,7 @@ describe Projects::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
platform_kubernetes_attributes: {
namespace: 'my-namespace'
}
@@ -464,6 +465,7 @@ describe Projects::ClustersController do
expect(flash[:notice]).to eq('Kubernetes cluster was successfully updated.')
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
expect(cluster.platform_kubernetes.namespace).to eq('my-namespace')
end
@@ -475,6 +477,7 @@ describe Projects::ClustersController do
cluster: {
enabled: false,
name: 'my-new-cluster-name',
+ managed: false,
platform_kubernetes_attributes: {
namespace: 'my-namespace'
}
@@ -489,6 +492,7 @@ describe Projects::ClustersController do
expect(response).to have_http_status(:no_content)
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
+ expect(cluster).not_to be_managed
expect(cluster.platform_kubernetes.namespace).to eq('my-namespace')
end
end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 3608d175d50..5c7f8d95f82 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -141,20 +141,6 @@ describe Projects::ServicesController do
end
end
- context 'with a deprecated service' do
- let(:service) { create(:kubernetes_service, project: project) }
-
- before do
- put :update,
- params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { namespace: 'updated_namespace' } }
- end
-
- it 'does not update the service' do
- service.reload
- expect(service.namespace).not_to eq('updated_namespace')
- end
- end
-
context 'when activating JIRA service from a template' do
let(:template_service) { create(:jira_service, project: project, template: true) }
@@ -168,20 +154,10 @@ describe Projects::ServicesController do
describe "GET #edit" do
before do
- get :edit, params: { namespace_id: project.namespace, project_id: project, id: service_id }
+ get :edit, params: { namespace_id: project.namespace, project_id: project, id: 'jira' }
end
context 'with approved services' do
- let(:service_id) { 'jira' }
-
- it 'renders edit page' do
- expect(response).to be_success
- end
- end
-
- context 'with a deprecated service' do
- let(:service_id) { 'kubernetes' }
-
it 'renders edit page' do
expect(response).to be_success
end
diff --git a/spec/factories/clusters/kubernetes_namespaces.rb b/spec/factories/clusters/kubernetes_namespaces.rb
index 3b50a57433f..042be7b4c4a 100644
--- a/spec/factories/clusters/kubernetes_namespaces.rb
+++ b/spec/factories/clusters/kubernetes_namespaces.rb
@@ -16,5 +16,9 @@ FactoryBot.define do
trait :with_token do
service_account_token { FFaker::Lorem.characters(10) }
end
+
+ trait :without_token do
+ service_account_token nil
+ end
end
end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 0d8c26a2ee9..763909f30bd 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -24,6 +24,8 @@ FactoryBot.define do
api_url: 'https://kubernetes.example.com',
token: 'a' * 40
})
+
+ skip_deprecation_validation true
end
factory :mock_deployment_service do
diff --git a/spec/features/projects/clusters/interchangeability_spec.rb b/spec/features/projects/clusters/interchangeability_spec.rb
deleted file mode 100644
index 0033e12b6b1..00000000000
--- a/spec/features/projects/clusters/interchangeability_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-describe 'Interchangeability between KubernetesService and Platform::Kubernetes' do
- EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url= deprecated? deprecation_message].freeze
- EXCEPT_METHODS_GREP_V = %w[_touched? _changed? _was].freeze
-
- it 'Clusters::Platform::Kubernetes covers core interfaces in KubernetesService' do
- expected_interfaces = KubernetesService.instance_methods(false)
- expected_interfaces = expected_interfaces - EXCEPT_METHODS
- EXCEPT_METHODS_GREP_V.each do |g|
- expected_interfaces = expected_interfaces.grep_v(/#{Regexp.escape(g)}\z/)
- end
-
- expect(expected_interfaces - Clusters::Platforms::Kubernetes.instance_methods).to be_empty
- end
-end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index da4ef6428d4..fbaf12be64e 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -155,7 +155,10 @@ describe 'Environment' do
end
context 'with terminal' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
+
context 'for project maintainer' do
let(:role) { :maintainer }
@@ -191,19 +194,6 @@ describe 'Environment' do
end
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project, :test_repo) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
context 'when environment is available' do
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 7b7e45312d9..1b5d9083932 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -248,7 +248,10 @@ describe 'Environments page', :js do
end
context 'when kubernetes terminal is available' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, projects: [create(:project, :repository)]) }
+ let(:project) { cluster.project }
+
context 'for project maintainer' do
let(:role) { :maintainer }
@@ -265,19 +268,6 @@ describe 'Environments page', :js do
end
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project, :test_repo) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let(:cluster) { create(:cluster, :provided_by_gcp, projects: [create(:project, :repository)]) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
end
diff --git a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
index 4884d5f8ba4..4510b82ca9d 100644
--- a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb
@@ -4,24 +4,14 @@ describe Gitlab::Ci::Build::Policy::Kubernetes do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when kubernetes service is active' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
- it 'is satisfied by a kubernetes pipeline' do
- expect(described_class.new('active'))
- .to be_satisfied_by(pipeline)
- end
- end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
+ it 'is satisfied by a kubernetes pipeline' do
+ expect(described_class.new('active'))
+ .to be_satisfied_by(pipeline)
+ end
end
end
diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
index 5387863bd07..5ac5122e800 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
@@ -35,9 +35,15 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
end
context 'and a namespace is already created for this project' do
- let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, project: build.project) }
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster, project: build.project) }
it { is_expected.to be_falsey }
+
+ context 'and the service_account_token is blank' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :without_token, cluster: cluster, project: build.project) }
+
+ it { is_expected.to be_truthy }
+ end
end
context 'and cluster is project type' do
diff --git a/spec/migrations/migrate_k8s_service_integration_spec.rb b/spec/migrations/migrate_k8s_service_integration_spec.rb
new file mode 100644
index 00000000000..4dd0c09632a
--- /dev/null
+++ b/spec/migrations/migrate_k8s_service_integration_spec.rb
@@ -0,0 +1,161 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20190517153211_migrate_k8s_service_integration.rb')
+
+describe MigrateK8sServiceIntegration, :migration do
+ context 'template service' do
+ context 'with namespace' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: true,
+ template: true,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}"
+ )
+ end
+
+ let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! }
+ let(:platform) { cluster.platform_kubernetes }
+
+ it 'migrates the KubernetesService template to Platform::Kubernetes' do
+ expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1)
+
+ expect(cluster).to be_enabled
+ expect(cluster).to be_user
+ expect(cluster).not_to be_managed
+ expect(cluster.environment_scope).to eq('*')
+ expect(platform.api_url).to eq('https://sample.kubernetes.com')
+ expect(platform.ca_cert).to eq('ca_pem-sample')
+ expect(platform.namespace).to eq('prod')
+ expect(platform.token).to eq('token-sample')
+ end
+ end
+
+ context 'without namespace' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: true,
+ template: true,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{\"namespace\":\"\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}"
+ )
+ end
+
+ let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! }
+ let(:platform) { cluster.platform_kubernetes }
+
+ it 'migrates the KubernetesService template to Platform::Kubernetes' do
+ expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1)
+
+ expect(cluster).to be_enabled
+ expect(cluster).to be_user
+ expect(cluster).not_to be_managed
+ expect(cluster.environment_scope).to eq('*')
+ expect(platform.api_url).to eq('https://sample.kubernetes.com')
+ expect(platform.ca_cert).to eq('ca_pem-sample')
+ expect(platform.namespace).to be_nil
+ expect(platform.token).to eq('token-sample')
+ end
+ end
+
+ context 'with nullified parameters' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: true,
+ template: true,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{}"
+ )
+ end
+
+ it 'does not migrate the KubernetesService' do
+ expect { migrate! }.not_to change { MigrateK8sServiceIntegration::Cluster.count }
+ end
+ end
+
+ context 'when disabled' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: false,
+ template: true,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}"
+ )
+ end
+
+ let(:cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! }
+ let(:platform) { cluster.platform_kubernetes }
+
+ it 'migrates the KubernetesService template to Platform::Kubernetes' do
+ expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1)
+
+ expect(cluster).not_to be_enabled
+ expect(cluster).to be_user
+ expect(cluster).not_to be_managed
+ expect(cluster.environment_scope).to eq('*')
+ expect(platform.api_url).to eq('https://sample.kubernetes.com')
+ expect(platform.ca_cert).to eq('ca_pem-sample')
+ expect(platform.namespace).to eq('prod')
+ expect(platform.token).to eq('token-sample')
+ end
+ end
+
+ context 'when an instance cluster already exists' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: true,
+ template: true,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}"
+ )
+ end
+
+ let!(:existing_cluster) do
+ MigrateK8sServiceIntegration::Cluster.create!(
+ name: 'test-cluster',
+ cluster_type: :instance_type,
+ managed: true,
+ provider_type: :user,
+ platform_type: :kubernetes
+ )
+ end
+ let(:new_cluster) { MigrateK8sServiceIntegration::Cluster.instance_type.last! }
+ let(:platform) { new_cluster.platform_kubernetes }
+
+ it 'migrates the KubernetesService template to disabled Platform::Kubernetes' do
+ expect { migrate! }.to change { MigrateK8sServiceIntegration::Cluster.count }.by(1)
+
+ expect(new_cluster).not_to be_enabled
+ expect(new_cluster).to be_user
+ expect(new_cluster).not_to be_managed
+ expect(new_cluster.environment_scope).to eq('*')
+ expect(platform.api_url).to eq('https://sample.kubernetes.com')
+ expect(platform.ca_cert).to eq('ca_pem-sample')
+ expect(platform.namespace).to eq('prod')
+ expect(platform.token).to eq('token-sample')
+ end
+ end
+ end
+
+ context 'non-template service' do
+ let!(:service) do
+ MigrateK8sServiceIntegration::Service.create!(
+ active: true,
+ template: false,
+ category: 'deployment',
+ type: 'KubernetesService',
+ properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}"
+ )
+ end
+
+ it 'does not migrate the KubernetesService' do
+ expect { migrate! }.not_to change { MigrateK8sServiceIntegration::Cluster.count }
+ end
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index c4e54be673f..6ebc6337d50 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -962,7 +962,11 @@ describe Ci::Pipeline, :mailer do
end
context 'when kubernetes is active' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
+ let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
+
it 'returns seeds for kubernetes dependent job' do
seeds = pipeline.stage_seeds
@@ -971,21 +975,6 @@ describe Ci::Pipeline, :mailer do
expect(seeds.dig(1, 0, :name)).to eq 'production'
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
- let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
- let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
context 'when kubernetes is not active' do
@@ -1679,23 +1668,13 @@ describe Ci::Pipeline, :mailer do
describe '#has_kubernetes_active?' do
context 'when kubernetes is active' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
- it 'returns true' do
- expect(pipeline).to have_kubernetes_active
- end
- end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
+ it 'returns true' do
+ expect(pipeline).to have_kubernetes_active
+ end
end
end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index f206bb41f45..52661178d76 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -514,19 +514,43 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
subject { cluster.allow_user_defined_namespace? }
context 'project type cluster' do
- it { is_expected.to be_truthy }
+ context 'gitlab managed' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'not managed' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, managed: false) }
+
+ it { is_expected.to be_truthy }
+ end
end
context 'group type cluster' do
- let(:cluster) { create(:cluster, :provided_by_gcp, :group) }
+ context 'gitlab managed' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :group) }
- it { is_expected.to be_falsey }
+ it { is_expected.to be_falsey }
+ end
+
+ context 'not managed' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :group, managed: false) }
+
+ it { is_expected.to be_truthy }
+ end
end
context 'instance type cluster' do
- let(:cluster) { create(:cluster, :provided_by_gcp, :instance) }
+ context 'gitlab managed' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :instance) }
- it { is_expected.to be_falsey }
+ it { is_expected.to be_falsey }
+ end
+
+ context 'not managed' do
+ let(:cluster) { create(:cluster, :provided_by_gcp, :instance, managed: false) }
+
+ it { is_expected.to be_truthy }
+ end
end
end
@@ -555,6 +579,63 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
end
+ describe '#find_or_initialize_kubernetes_namespace_for_project' do
+ let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.projects.first }
+
+ subject { cluster.find_or_initialize_kubernetes_namespace_for_project(project) }
+
+ context 'kubernetes namespace exists' do
+ context 'with no service account token' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, project: project, cluster: cluster) }
+
+ it { is_expected.to eq kubernetes_namespace }
+ end
+
+ context 'with a service account token' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, project: project, cluster: cluster) }
+
+ it { is_expected.to eq kubernetes_namespace }
+ end
+ end
+
+ context 'kubernetes namespace does not exist' do
+ it 'initializes a new namespace and sets default values' do
+ expect(subject).to be_new_record
+ expect(subject.project).to eq project
+ expect(subject.cluster).to eq cluster
+ expect(subject.namespace).to be_present
+ expect(subject.service_account_name).to be_present
+ end
+ end
+
+ context 'a custom scope is provided' do
+ let(:scope) { cluster.kubernetes_namespaces.has_service_account_token }
+
+ subject { cluster.find_or_initialize_kubernetes_namespace_for_project(project, scope: scope) }
+
+ context 'kubernetes namespace exists' do
+ context 'with no service account token' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, project: project, cluster: cluster) }
+
+ it 'initializes a new namespace and sets default values' do
+ expect(subject).to be_new_record
+ expect(subject.project).to eq project
+ expect(subject.cluster).to eq cluster
+ expect(subject.namespace).to be_present
+ expect(subject.service_account_name).to be_present
+ end
+ end
+
+ context 'with a service account token' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, project: project, cluster: cluster) }
+
+ it { is_expected.to eq kubernetes_namespace }
+ end
+ end
+ end
+ end
+
describe '#predefined_variables' do
subject { cluster.predefined_variables }
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index c485850c16e..1fb3a8de808 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -223,19 +223,33 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
let(:namespace) { 'namespace-123' }
it { is_expected.to eq(namespace) }
+
+ context 'kubernetes namespace is present but has no service account token' do
+ let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) }
+
+ it { is_expected.to eq(namespace) }
+ end
end
context 'with no namespace assigned' do
let(:namespace) { nil }
context 'when kubernetes namespace is present' do
- let(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) }
+ let(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token, cluster: cluster) }
before do
kubernetes_namespace
end
it { is_expected.to eq(kubernetes_namespace.namespace) }
+
+ context 'kubernetes namespace has no service account token' do
+ before do
+ kubernetes_namespace.update!(namespace: 'old-namespace', service_account_token: nil)
+ end
+
+ it { is_expected.to eq("#{project.path}-#{project.id}") }
+ end
end
context 'when kubernetes namespace is not present' do
@@ -284,6 +298,46 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
{ key: 'KUBE_TOKEN', value: kubernetes_namespace.service_account_token, public: false, masked: true }
)
end
+
+ context 'the cluster has been set to unmanaged after the namespace was created' do
+ before do
+ cluster.update!(managed: false)
+ end
+
+ it_behaves_like 'setting variables'
+
+ it 'sets KUBE_TOKEN from the platform' do
+ expect(subject).to include(
+ { key: 'KUBE_TOKEN', value: kubernetes.token, public: false, masked: true }
+ )
+ end
+
+ context 'the platform has a custom namespace set' do
+ before do
+ kubernetes.update!(namespace: 'custom-namespace')
+ end
+
+ it 'sets KUBE_NAMESPACE from the platform' do
+ expect(subject).to include(
+ { key: 'KUBE_NAMESPACE', value: kubernetes.namespace, public: true, masked: false }
+ )
+ end
+ end
+
+ context 'there is no namespace specified on the platform' do
+ let(:project) { cluster.project }
+
+ before do
+ kubernetes.update!(namespace: nil)
+ end
+
+ it 'sets KUBE_NAMESPACE to a default for the project' do
+ expect(subject).to include(
+ { key: 'KUBE_NAMESPACE', value: "#{project.path}-#{project.id}", public: true, masked: false }
+ )
+ end
+ end
+ end
end
context 'namespace is provided' do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 7233d2454c6..379dda1f5c4 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -515,29 +515,19 @@ describe Environment do
context 'when the environment is available' do
context 'with a deployment service' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
- context 'and a deployment' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
+
+ context 'with deployment' do
let!(:deployment) { create(:deployment, :success, environment: environment) }
it { is_expected.to be_truthy }
end
- context 'but no deployments' do
+ context 'without deployments' do
it { is_expected.to be_falsy }
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
context 'without a deployment service' do
@@ -546,8 +536,6 @@ describe Environment do
end
context 'when the environment is unavailable' do
- let(:project) { create(:kubernetes_project) }
-
before do
environment.stop
end
@@ -590,7 +578,10 @@ describe Environment do
allow(environment).to receive(:has_terminals?).and_return(true)
end
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
+
it 'returns the terminals from the deployment service' do
expect(environment.deployment_platform)
.to receive(:terminals).with(environment)
@@ -599,19 +590,6 @@ describe Environment do
is_expected.to eq(:fake_terminals)
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
context 'when the environment does not have terminals' do
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 2fce120381b..34ee1eafd5c 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -17,6 +17,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
context 'when service is active' do
before do
subject.active = true
+ subject.skip_deprecation_validation = true
end
it { is_expected.not_to validate_presence_of(:namespace) }
@@ -67,6 +68,7 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
before do
kubernetes_service.update_attribute(:active, false)
+ kubernetes_service.skip_deprecation_validation = false
kubernetes_service.properties['namespace'] = "foo"
end
@@ -80,19 +82,11 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
end
- context 'with a non-deprecated service' do
- let(:kubernetes_service) { create(:kubernetes_service) }
-
- it 'updates attributes' do
- kubernetes_service.properties['namespace'] = 'foo'
- expect(kubernetes_service.save).to be_truthy
- end
- end
-
context 'with an active and deprecated service' do
let(:kubernetes_service) { create(:kubernetes_service) }
before do
+ kubernetes_service.skip_deprecation_validation = false
kubernetes_service.active = false
kubernetes_service.properties['namespace'] = 'foo'
kubernetes_service.save
@@ -110,19 +104,6 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
expect(kubernetes_service.properties['namespace']).to eq("foo")
end
end
-
- context 'with a template service' do
- let(:kubernetes_service) { create(:kubernetes_service, template: true, active: false) }
-
- before do
- kubernetes_service.properties['namespace'] = 'foo'
- end
-
- it 'updates attributes' do
- expect(kubernetes_service.save).to be_truthy
- expect(kubernetes_service.properties['namespace']).to eq('foo')
- end
- end
end
describe '#initialize_properties' do
@@ -393,17 +374,8 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
describe "#deprecated?" do
let(:kubernetes_service) { create(:kubernetes_service) }
- context 'with an active kubernetes service' do
- it 'returns false' do
- expect(kubernetes_service.deprecated?).to be_falsy
- end
- end
-
- context 'with a inactive kubernetes service' do
- it 'returns true' do
- kubernetes_service.update_attribute(:active, false)
- expect(kubernetes_service.deprecated?).to be_truthy
- end
+ it 'returns true' do
+ expect(kubernetes_service.deprecated?).to be_truthy
end
end
@@ -414,12 +386,6 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been deprecated/)
end
- context 'if the services is active' do
- it 'returns a message' do
- expect(kubernetes_service.deprecation_message).to match(/Your Kubernetes cluster information on this page is still editable/)
- end
- end
-
context 'if the service is not active' do
it 'returns a message' do
kubernetes_service.update_attribute(:active, false)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 269d2bb90d3..20b98b5eb85 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2652,7 +2652,10 @@ describe Project do
end
context 'when project has a deployment service' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has not been executed' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
+
it 'returns variables from this service' do
expect(project.deployment_variables).to include(
{ key: 'KUBE_TOKEN', value: project.deployment_platform.token, public: false, masked: true }
@@ -2660,19 +2663,6 @@ describe Project do
end
end
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has not been executed' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
context 'when user configured kubernetes from CI/CD > Clusters and KubernetesNamespace migration has been executed' do
let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, :with_token) }
let!(:cluster) { kubernetes_namespace.cluster }
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index c9439b0846d..d442c73c118 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -82,7 +82,7 @@ describe Service do
context 'when template is invalid' do
it 'sets service template to inactive when template is invalid' do
project = create(:project)
- template = KubernetesService.new(template: true, active: true)
+ template = build(:prometheus_service, template: true, active: true, properties: {})
template.save(validate: false)
service = described_class.build_from_template(project.id, template)
@@ -309,10 +309,10 @@ describe Service do
end
describe '.find_by_template' do
- let!(:kubernetes_service) { create(:kubernetes_service, template: true) }
+ let!(:service) { create(:service, template: true) }
it 'returns service template' do
- expect(KubernetesService.find_by_template).to eq(kubernetes_service)
+ expect(described_class.find_by_template).to eq(service)
end
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index e260aa21e25..3f79e332b90 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -10,7 +10,10 @@ describe API::Services do
end
Service.available_services_names.each do |service|
- describe "PUT /projects/:id/services/#{service.dasherize}" do
+ # TODO: Remove below `if: (service != "kubernetes")` in the next release
+ # KubernetesService was deprecated and it can't be updated. Right now it's
+ # only readable. It should be completely removed in the next iteration.
+ describe "PUT /projects/:id/services/#{service.dasherize}", if: (service != "kubernetes") do
include_context service
it "updates #{service} settings" do
@@ -19,13 +22,22 @@ describe API::Services do
expect(response).to have_gitlab_http_status(200)
current_service = project.services.first
- event = current_service.event_names.empty? ? "foo" : current_service.event_names.first
- state = current_service[event] || false
+ events = current_service.event_names.empty? ? ["foo"].freeze : current_service.event_names
+ query_strings = []
+ events.each do |event|
+ query_strings << "#{event}=#{!current_service[event]}"
+ end
+ query_strings = query_strings.join('&')
- put api("/projects/#{project.id}/services/#{dashed_service}?#{event}=#{!state}", user), params: service_attrs
+ put api("/projects/#{project.id}/services/#{dashed_service}?#{query_strings}", user), params: service_attrs
expect(response).to have_gitlab_http_status(200)
- expect(project.services.first[event]).not_to eq(state) unless event == "foo"
+ events.each do |event|
+ next if event == "foo"
+
+ expect(project.services.first[event]).not_to eq(current_service[event]),
+ "expected #{!current_service[event]} for event #{event} for service #{current_service.title}, got #{current_service[event]}"
+ end
end
it "returns if required fields missing" do
@@ -50,7 +62,10 @@ describe API::Services do
end
end
- describe "DELETE /projects/:id/services/#{service.dasherize}" do
+ # TODO: Remove below `if: (service != "kubernetes")` in the next release
+ # KubernetesService was deprecated and it can't be updated. Right now it's
+ # only readable. It should be completely removed in the next iteration.
+ describe "DELETE /projects/:id/services/#{service.dasherize}", if: (service != "kubernetes") do
include_context service
before do
diff --git a/spec/serializers/environment_entity_spec.rb b/spec/serializers/environment_entity_spec.rb
index c2312734042..906449f470b 100644
--- a/spec/serializers/environment_entity_spec.rb
+++ b/spec/serializers/environment_entity_spec.rb
@@ -59,15 +59,5 @@ describe EnvironmentEntity do
expect(subject[:cluster_type]).to eq('project_type')
end
end
-
- context 'when deployment platform is a Kubernetes Service' do
- before do
- create(:kubernetes_service, project: project)
- end
-
- it 'does not include cluster_type' do
- expect(subject).not_to include(:cluster_type)
- end
- end
end
end
diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb
index 8044b061ca5..de21e808932 100644
--- a/spec/support/prometheus/additional_metrics_shared_examples.rb
+++ b/spec/support/prometheus/additional_metrics_shared_examples.rb
@@ -44,7 +44,9 @@ RSpec.shared_examples 'additional metrics query' do
end
describe 'project has Kubernetes service' do
- shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
+ context 'when user configured kubernetes from CI/CD > Clusters' do
+ let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
let(:kube_namespace) { project.deployment_platform.kubernetes_namespace_for(project) }
@@ -56,19 +58,6 @@ RSpec.shared_examples 'additional metrics query' do
subject.query(*query_params)
end
end
-
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
-
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
- end
end
describe 'project without Kubernetes service' do
diff --git a/spec/support/shared_contexts/services_shared_context.rb b/spec/support/shared_contexts/services_shared_context.rb
index 089f1798cd2..0c3a24d206f 100644
--- a/spec/support/shared_contexts/services_shared_context.rb
+++ b/spec/support/shared_contexts/services_shared_context.rb
@@ -37,8 +37,7 @@ Service.available_services_names.each do |service|
def initialize_service(service)
service_item = project.find_or_initialize_service(service)
service_item.properties = service_attrs
- service_item.active = true if service == "kubernetes"
- service_item.save
+ service_item.save!
service_item
end
end
diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb
index 2395e6ec947..b8ca6063ccd 100644
--- a/spec/workers/reactive_caching_worker_spec.rb
+++ b/spec/workers/reactive_caching_worker_spec.rb
@@ -6,16 +6,6 @@ describe ReactiveCachingWorker do
let(:service) { project.deployment_platform }
describe '#perform' do
- context 'when user configured kubernetes from Integration > Kubernetes' do
- let(:project) { create(:kubernetes_project) }
-
- it 'calls #exclusively_update_reactive_cache!' do
- expect_any_instance_of(KubernetesService).to receive(:exclusively_update_reactive_cache!)
-
- described_class.new.perform("KubernetesService", service.id)
- end
- end
-
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }