diff options
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/clusters/create_service.rb | 22 | ||||
-rw-r--r-- | app/services/clusters/gcp/finalize_creation_service.rb | 23 | ||||
-rw-r--r-- | app/services/clusters/gcp/kubernetes.rb | 11 | ||||
-rw-r--r-- | app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb | 54 | ||||
-rw-r--r-- | app/services/clusters/gcp/kubernetes/create_service_account_service.rb | 78 | ||||
-rw-r--r-- | app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb | 8 | ||||
-rw-r--r-- | app/services/issuable_base_service.rb | 8 | ||||
-rw-r--r-- | app/services/issues/update_service.rb | 14 | ||||
-rw-r--r-- | app/services/merge_requests/refresh_service.rb | 11 | ||||
-rw-r--r-- | app/services/merge_requests/reload_diffs_service.rb | 5 | ||||
-rw-r--r-- | app/services/merge_requests/update_service.rb | 14 | ||||
-rw-r--r-- | app/services/milestones/destroy_service.rb | 2 | ||||
-rw-r--r-- | app/services/notification_service.rb | 41 |
13 files changed, 253 insertions, 38 deletions
diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb index cd843b8ffa8..270db4a52fd 100644 --- a/app/services/clusters/create_service.rb +++ b/app/services/clusters/create_service.rb @@ -8,10 +8,11 @@ module Clusters @current_user, @params = user, params.dup end - def execute(project:, access_token: nil) - raise ArgumentError, _('Instance does not support multiple Kubernetes clusters') unless can_create_cluster?(project) + def execute(access_token: nil) + raise ArgumentError, 'Unknown clusterable provided' unless clusterable + raise ArgumentError, _('Instance does not support multiple Kubernetes clusters') unless can_create_cluster? - cluster_params = params.merge(user: current_user, cluster_type: :project_type, projects: [project]) + cluster_params = params.merge(user: current_user).merge(clusterable_params) cluster_params[:provider_gcp_attributes].try do |provider| provider[:access_token] = access_token end @@ -27,9 +28,20 @@ module Clusters Clusters::Cluster.create(cluster_params) end + def clusterable + @clusterable ||= params.delete(:clusterable) + end + + def clusterable_params + case clusterable + when ::Project + { cluster_type: :project_type, projects: [clusterable] } + end + end + # EE would override this method - def can_create_cluster?(project) - project.clusters.empty? + def can_create_cluster? + clusterable.clusters.empty? end end end diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb index 6ee63db8eb9..3df43657fa0 100644 --- a/app/services/clusters/gcp/finalize_creation_service.rb +++ b/app/services/clusters/gcp/finalize_creation_service.rb @@ -11,8 +11,9 @@ module Clusters configure_provider create_gitlab_service_account! configure_kubernetes - cluster.save! + configure_project_service_account + rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e provider.make_errored!("Failed to request to CloudPlatform; #{e.message}") rescue Kubeclient::HttpError => e @@ -24,7 +25,10 @@ module Clusters private def create_gitlab_service_account! - Clusters::Gcp::Kubernetes::CreateServiceAccountService.new(kube_client, rbac: create_rbac_cluster?).execute + Clusters::Gcp::Kubernetes::CreateServiceAccountService.gitlab_creator( + kube_client, + rbac: create_rbac_cluster? + ).execute end def configure_provider @@ -44,7 +48,20 @@ module Clusters end def request_kubernetes_token - Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new(kube_client).execute + Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new( + kube_client, + Clusters::Gcp::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, + Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE + ).execute + end + + def configure_project_service_account + kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace(cluster.cluster_project) + + Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( + cluster: cluster, + kubernetes_namespace: kubernetes_namespace + ).execute end def authorization_type diff --git a/app/services/clusters/gcp/kubernetes.rb b/app/services/clusters/gcp/kubernetes.rb index d014d73b3e8..90ed529670c 100644 --- a/app/services/clusters/gcp/kubernetes.rb +++ b/app/services/clusters/gcp/kubernetes.rb @@ -3,11 +3,12 @@ module Clusters module Gcp module Kubernetes - SERVICE_ACCOUNT_NAME = 'gitlab' - SERVICE_ACCOUNT_NAMESPACE = 'default' - SERVICE_ACCOUNT_TOKEN_NAME = 'gitlab-token' - CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin' - CLUSTER_ROLE_NAME = 'cluster-admin' + GITLAB_SERVICE_ACCOUNT_NAME = 'gitlab' + GITLAB_SERVICE_ACCOUNT_NAMESPACE = 'default' + GITLAB_ADMIN_TOKEN_NAME = 'gitlab-token' + GITLAB_CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin' + GITLAB_CLUSTER_ROLE_NAME = 'cluster-admin' + PROJECT_CLUSTER_ROLE_NAME = 'edit' end end end diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb new file mode 100644 index 00000000000..a888fab2789 --- /dev/null +++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Clusters + module Gcp + module Kubernetes + class CreateOrUpdateNamespaceService + def initialize(cluster:, kubernetes_namespace:) + @cluster = cluster + @kubernetes_namespace = kubernetes_namespace + @platform = cluster.platform + end + + def execute + configure_kubernetes_namespace + create_project_service_account + configure_kubernetes_token + + kubernetes_namespace.save! + rescue ::Kubeclient::HttpError => err + raise err unless err.error_code = 404 + end + + private + + attr_reader :cluster, :kubernetes_namespace, :platform + + def configure_kubernetes_namespace + kubernetes_namespace.configure_predefined_credentials + end + + def create_project_service_account + Clusters::Gcp::Kubernetes::CreateServiceAccountService.namespace_creator( + platform.kubeclient, + service_account_name: kubernetes_namespace.service_account_name, + service_account_namespace: kubernetes_namespace.namespace, + rbac: platform.rbac? + ).execute + end + + def configure_kubernetes_token + kubernetes_namespace.service_account_token = fetch_service_account_token + end + + def fetch_service_account_token + Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new( + platform.kubeclient, + kubernetes_namespace.token_name, + kubernetes_namespace.namespace + ).execute + end + end + end + end +end diff --git a/app/services/clusters/gcp/kubernetes/create_service_account_service.rb b/app/services/clusters/gcp/kubernetes/create_service_account_service.rb index d17744591e6..dfc4bf7a358 100644 --- a/app/services/clusters/gcp/kubernetes/create_service_account_service.rb +++ b/app/services/clusters/gcp/kubernetes/create_service_account_service.rb @@ -4,46 +4,96 @@ module Clusters module Gcp module Kubernetes class CreateServiceAccountService - attr_reader :kubeclient, :rbac - - def initialize(kubeclient, rbac:) + def initialize(kubeclient, service_account_name:, service_account_namespace:, token_name:, rbac:, namespace_creator: false, role_binding_name: nil) @kubeclient = kubeclient + @service_account_name = service_account_name + @service_account_namespace = service_account_namespace + @token_name = token_name @rbac = rbac + @namespace_creator = namespace_creator + @role_binding_name = role_binding_name + end + + def self.gitlab_creator(kubeclient, rbac:) + self.new( + kubeclient, + service_account_name: Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAME, + service_account_namespace: Clusters::Gcp::Kubernetes::GITLAB_SERVICE_ACCOUNT_NAMESPACE, + token_name: Clusters::Gcp::Kubernetes::GITLAB_ADMIN_TOKEN_NAME, + rbac: rbac + ) + end + + def self.namespace_creator(kubeclient, service_account_name:, service_account_namespace:, rbac:) + self.new( + kubeclient, + service_account_name: service_account_name, + service_account_namespace: service_account_namespace, + token_name: "#{service_account_namespace}-token", + rbac: rbac, + namespace_creator: true, + role_binding_name: "gitlab-#{service_account_namespace}" + ) end def execute + ensure_project_namespace_exists if namespace_creator kubeclient.create_service_account(service_account_resource) kubeclient.create_secret(service_account_token_resource) - kubeclient.create_cluster_role_binding(cluster_role_binding_resource) if rbac + create_role_or_cluster_role_binding if rbac end private + attr_reader :kubeclient, :service_account_name, :service_account_namespace, :token_name, :rbac, :namespace_creator, :role_binding_name + + def ensure_project_namespace_exists + Gitlab::Kubernetes::Namespace.new( + service_account_namespace, + kubeclient + ).ensure_exists! + end + + def create_role_or_cluster_role_binding + if namespace_creator + kubeclient.create_role_binding(role_binding_resource) + else + kubeclient.create_cluster_role_binding(cluster_role_binding_resource) + end + end + def service_account_resource - Gitlab::Kubernetes::ServiceAccount.new(service_account_name, service_account_namespace).generate + Gitlab::Kubernetes::ServiceAccount.new( + service_account_name, + service_account_namespace + ).generate end def service_account_token_resource Gitlab::Kubernetes::ServiceAccountToken.new( - SERVICE_ACCOUNT_TOKEN_NAME, service_account_name, service_account_namespace).generate + token_name, + service_account_name, + service_account_namespace + ).generate end def cluster_role_binding_resource subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }] Gitlab::Kubernetes::ClusterRoleBinding.new( - CLUSTER_ROLE_BINDING_NAME, - CLUSTER_ROLE_NAME, + Clusters::Gcp::Kubernetes::GITLAB_CLUSTER_ROLE_BINDING_NAME, + Clusters::Gcp::Kubernetes::GITLAB_CLUSTER_ROLE_NAME, subjects ).generate end - def service_account_name - SERVICE_ACCOUNT_NAME - end - - def service_account_namespace - SERVICE_ACCOUNT_NAMESPACE + def role_binding_resource + Gitlab::Kubernetes::RoleBinding.new( + name: role_binding_name, + role_name: Clusters::Gcp::Kubernetes::PROJECT_CLUSTER_ROLE_NAME, + namespace: service_account_namespace, + service_account_name: service_account_name + ).generate end end end diff --git a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb index 9e09345c8dc..277cc4b788d 100644 --- a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb +++ b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb @@ -4,10 +4,12 @@ module Clusters module Gcp module Kubernetes class FetchKubernetesTokenService - attr_reader :kubeclient + attr_reader :kubeclient, :service_account_token_name, :namespace - def initialize(kubeclient) + def initialize(kubeclient, service_account_token_name, namespace) @kubeclient = kubeclient + @service_account_token_name = service_account_token_name + @namespace = namespace end def execute @@ -18,7 +20,7 @@ module Clusters private def get_secret - kubeclient.get_secret(SERVICE_ACCOUNT_TOKEN_NAME, SERVICE_ACCOUNT_NAMESPACE).as_json + kubeclient.get_secret(service_account_token_name, namespace).as_json rescue Kubeclient::HttpError => err raise err unless err.error_code == 404 diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 3e8b9f84042..c388913ae65 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -3,6 +3,14 @@ class IssuableBaseService < BaseService private + attr_accessor :params, :skip_milestone_email + + def initialize(project, user = nil, params = {}) + super + + @skip_milestone_email = @params.delete(:skip_milestone_email) + end + def filter_params(issuable) ability_name = :"admin_#{issuable.to_ability_name}" diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index b54b0bf6ef6..fba252b0bae 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -48,6 +48,8 @@ module Issues notification_service.async.relabeled_issue(issue, added_labels, current_user) end + handle_milestone_change(issue) + added_mentions = issue.mentioned_users - old_mentioned_users if added_mentions.present? @@ -91,6 +93,18 @@ module Issues private + def handle_milestone_change(issue) + return if skip_milestone_email + + return unless issue.previous_changes.include?('milestone_id') + + if issue.milestone.nil? + notification_service.async.removed_milestone_issue(issue, current_user) + else + notification_service.async.changed_milestone_issue(issue, issue.milestone, current_user) + end + end + # rubocop: disable CodeReuse/ActiveRecord def get_issue_if_allowed(id, board_group_id = nil) return unless id diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index f01872b205e..53768ff2cbe 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -87,11 +87,8 @@ module MergeRequests filter_merge_requests(merge_requests).each do |merge_request| if branch_and_project_match?(merge_request) || @push.force_push? merge_request.reload_diff(current_user) - else - mr_commit_ids = merge_request.commit_shas - push_commit_ids = @commits.map(&:id) - matches = mr_commit_ids & push_commit_ids - merge_request.reload_diff(current_user) if matches.any? + elsif merge_request.includes_any_commits?(push_commit_ids) + merge_request.reload_diff(current_user) end merge_request.mark_as_unchecked @@ -104,6 +101,10 @@ module MergeRequests end # rubocop: enable CodeReuse/ActiveRecord + def push_commit_ids + @push_commit_ids ||= @commits.map(&:id) + end + def branch_and_project_match?(merge_request) merge_request.source_project == @project && merge_request.source_branch == @push.branch_name diff --git a/app/services/merge_requests/reload_diffs_service.rb b/app/services/merge_requests/reload_diffs_service.rb index b4d48fe92ad..b47d8f3f63a 100644 --- a/app/services/merge_requests/reload_diffs_service.rb +++ b/app/services/merge_requests/reload_diffs_service.rb @@ -36,7 +36,10 @@ module MergeRequests # Remove cache for all diffs on this MR. Do not use the association on the # model, as that will interfere with other actions happening when # reloading the diff. - MergeRequestDiff.where(merge_request: merge_request).each do |merge_request_diff| + MergeRequestDiff + .where(merge_request: merge_request) + .preload(merge_request: :target_project) + .find_each do |merge_request_diff| next if merge_request_diff == new_diff cacheable_collection(merge_request_diff).clear_cache diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index b112edbce7f..aacaf10d09c 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -58,6 +58,8 @@ module MergeRequests merge_request.mark_as_unchecked end + handle_milestone_change(merge_request) + added_labels = merge_request.labels - old_labels if added_labels.present? notification_service.async.relabeled_merge_request( @@ -105,6 +107,18 @@ module MergeRequests private + def handle_milestone_change(merge_request) + return if skip_milestone_email + + return unless merge_request.previous_changes.include?('milestone_id') + + if merge_request.milestone.nil? + notification_service.async.removed_milestone_merge_request(merge_request, current_user) + else + notification_service.async.changed_milestone_merge_request(merge_request, merge_request.milestone, current_user) + end + end + def create_branch_change_note(issuable, branch_type, old_branch, new_branch) SystemNoteService.change_branch( issuable, issuable.project, current_user, branch_type, diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb index 7cda802c120..87c7a282081 100644 --- a/app/services/milestones/destroy_service.rb +++ b/app/services/milestones/destroy_service.rb @@ -4,7 +4,7 @@ module Milestones class DestroyService < Milestones::BaseService def execute(milestone) Milestone.transaction do - update_params = { milestone: nil } + update_params = { milestone: nil, skip_milestone_email: true } milestone.issues.each do |issue| Issues::UpdateService.new(parent, current_user, update_params).execute(issue) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 50fa373025b..fb9c18ea75d 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -129,6 +129,14 @@ class NotificationService relabeled_resource_email(issue, added_labels, current_user, :relabeled_issue_email) end + def removed_milestone_issue(issue, current_user) + removed_milestone_resource_email(issue, current_user, :removed_milestone_issue_email) + end + + def changed_milestone_issue(issue, new_milestone, current_user) + changed_milestone_resource_email(issue, new_milestone, current_user, :changed_milestone_issue_email) + end + # When create a merge request we should send an email to: # # * mr author @@ -138,7 +146,6 @@ class NotificationService # * users with custom level checked with "new merge request" # # In EE, approvers of the merge request are also included - # def new_merge_request(merge_request, current_user) new_resource_email(merge_request, :new_merge_request_email) end @@ -208,6 +215,14 @@ class NotificationService relabeled_resource_email(merge_request, added_labels, current_user, :relabeled_merge_request_email) end + def removed_milestone_merge_request(merge_request, current_user) + removed_milestone_resource_email(merge_request, current_user, :removed_milestone_merge_request_email) + end + + def changed_milestone_merge_request(merge_request, new_milestone, current_user) + changed_milestone_resource_email(merge_request, new_milestone, current_user, :changed_milestone_merge_request_email) + end + def close_mr(merge_request, current_user) close_resource_email(merge_request, current_user, :closed_merge_request_email) end @@ -500,6 +515,30 @@ class NotificationService end end + def removed_milestone_resource_email(target, current_user, method) + recipients = NotificationRecipientService.build_recipients( + target, + current_user, + action: 'removed_milestone' + ) + + recipients.each do |recipient| + mailer.send(method, recipient.user.id, target.id, current_user.id).deliver_later + end + end + + def changed_milestone_resource_email(target, milestone, current_user, method) + recipients = NotificationRecipientService.build_recipients( + target, + current_user, + action: 'changed_milestone' + ) + + recipients.each do |recipient| + mailer.send(method, recipient.user.id, target.id, milestone, current_user.id).deliver_later + end + end + def reopen_resource_email(target, current_user, method, status) recipients = NotificationRecipientService.build_recipients(target, current_user, action: "reopen") |