diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-24 12:09:25 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-24 12:09:25 +0300 |
commit | 6f7881ee9dcec34141a8f34fc814b56b366d2b48 (patch) | |
tree | 25f72a06874b32b1049b79a9d7f4f1b7bca43b9b /app/services/clusters | |
parent | 8c8bf44fa64f98114f7439f751c92d59a44b3218 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/services/clusters')
4 files changed, 299 insertions, 0 deletions
diff --git a/app/services/clusters/applications/check_upgrade_progress_service.rb b/app/services/clusters/applications/check_upgrade_progress_service.rb new file mode 100644 index 00000000000..8502ea69f27 --- /dev/null +++ b/app/services/clusters/applications/check_upgrade_progress_service.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class CheckUpgradeProgressService < BaseHelmService + def execute + return unless app.updating? + + case phase + when ::Gitlab::Kubernetes::Pod::SUCCEEDED + on_success + when ::Gitlab::Kubernetes::Pod::FAILED + on_failed + else + check_timeout + end + rescue ::Kubeclient::HttpError => e + app.make_update_errored!("Kubernetes error: #{e.message}") unless app.update_errored? + end + + private + + def on_success + app.make_installed! + ensure + remove_pod + end + + def on_failed + app.make_update_errored!(errors || 'Update silently failed') + ensure + remove_pod + end + + def check_timeout + if timed_out? + begin + app.make_update_errored!('Update timed out') + ensure + remove_pod + end + else + ::ClusterWaitForAppUpdateWorker.perform_in( + ::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id) + end + end + + def timed_out? + Time.now.utc - app.updated_at.to_time.utc > ::ClusterWaitForAppUpdateWorker::TIMEOUT + end + + def remove_pod + helm_api.delete_pod!(pod_name) + rescue + # no-op + end + + def phase + helm_api.status(pod_name) + end + + def errors + helm_api.log(pod_name) + end + + def pod_name + @pod_name ||= patch_command.pod_name + end + end + end +end diff --git a/app/services/clusters/applications/prometheus_config_service.rb b/app/services/clusters/applications/prometheus_config_service.rb new file mode 100644 index 00000000000..34d44ab881e --- /dev/null +++ b/app/services/clusters/applications/prometheus_config_service.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class PrometheusConfigService + def initialize(project, cluster, app) + @project = project + @cluster = cluster + @app = app + end + + def execute(config = {}) + if has_alerts? + generate_alert_manager(config) + else + reset_alert_manager(config) + end + end + + private + + attr_reader :project, :cluster, :app + + def reset_alert_manager(config) + config = set_alert_manager_enabled(config, false) + config.delete('alertmanagerFiles') + config['serverFiles'] ||= {} + config['serverFiles']['alerts'] = {} + + config + end + + def generate_alert_manager(config) + config = set_alert_manager_enabled(config, true) + config = set_alert_manager_files(config) + + set_alert_manager_groups(config) + end + + def set_alert_manager_enabled(config, enabled) + config['alertmanager'] ||= {} + config['alertmanager']['enabled'] = enabled + + config + end + + def set_alert_manager_files(config) + config['alertmanagerFiles'] = { + 'alertmanager.yml' => { + 'receivers' => alert_manager_receivers_params, + 'route' => alert_manager_route_params + } + } + + config + end + + def set_alert_manager_groups(config) + config['serverFiles'] ||= {} + config['serverFiles']['alerts'] ||= {} + config['serverFiles']['alerts']['groups'] ||= [] + + environments_with_alerts.each do |env_name, alerts| + index = config['serverFiles']['alerts']['groups'].find_index do |group| + group['name'] == env_name + end + + if index + config['serverFiles']['alerts']['groups'][index]['rules'] = alerts + else + config['serverFiles']['alerts']['groups'] << { + 'name' => env_name, + 'rules' => alerts + } + end + end + + config + end + + def alert_manager_receivers_params + [ + { + 'name' => 'gitlab', + 'webhook_configs' => [ + { + 'url' => notify_url, + 'send_resolved' => true, + 'http_config' => { + 'bearer_token' => alert_manager_token + } + } + ] + } + ] + end + + def alert_manager_token + app.generate_alert_manager_token! + + app.alert_manager_token + end + + def alert_manager_route_params + { + 'receiver' => 'gitlab', + 'group_wait' => '30s', + 'group_interval' => '5m', + 'repeat_interval' => '4h' + } + end + + def notify_url + ::Gitlab::Routing.url_helpers + .notify_project_prometheus_alerts_url(project, format: :json) + end + + def has_alerts? + environments_with_alerts.values.flatten(1).any? + end + + def environments_with_alerts + @environments_with_alerts ||= + environments.each_with_object({}) do |environment, hash| + name = rule_name(environment) + hash[name] = alerts(environment) + end + end + + def rule_name(environment) + "#{environment.name}.rules" + end + + def alerts(environment) + variables = Gitlab::Prometheus::QueryVariables.call(environment) + alerts = Projects::Prometheus::AlertsFinder + .new(environment: environment) + .execute + + alerts.map do |alert| + substitute_query_variables(alert.to_param, variables) + end + end + + def substitute_query_variables(hash, variables) + hash['expr'] %= variables + hash + end + + def environments + project.environments_for_scope(cluster.environment_scope) + end + end + end +end diff --git a/app/services/clusters/applications/prometheus_update_service.rb b/app/services/clusters/applications/prometheus_update_service.rb new file mode 100644 index 00000000000..437f6ab1202 --- /dev/null +++ b/app/services/clusters/applications/prometheus_update_service.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class PrometheusUpdateService < BaseHelmService + attr_accessor :project + + def initialize(app, project) + super(app) + @project = project + end + + def execute + app.make_updating! + + helm_api.update(patch_command(values)) + + ::ClusterWaitForAppUpdateWorker.perform_in(::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id) + rescue ::Kubeclient::HttpError => ke + app.make_update_errored!("Kubernetes error: #{ke.message}") + rescue StandardError => e + app.make_update_errored!(e.message) + end + + private + + def values + PrometheusConfigService + .new(project, cluster, app) + .execute + .to_yaml + end + end + end +end diff --git a/app/services/clusters/applications/schedule_update_service.rb b/app/services/clusters/applications/schedule_update_service.rb new file mode 100644 index 00000000000..b7639c771a8 --- /dev/null +++ b/app/services/clusters/applications/schedule_update_service.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Clusters + module Applications + class ScheduleUpdateService + BACKOFF_DELAY = 2.minutes + + attr_accessor :application, :project + + def initialize(application, project) + @application = application + @project = project + end + + def execute + return unless application + + if recently_scheduled? + worker_class.perform_in(BACKOFF_DELAY, application.name, application.id, project.id, Time.now) + else + worker_class.perform_async(application.name, application.id, project.id, Time.now) + end + end + + private + + def worker_class + ::ClusterUpdateAppWorker + end + + def recently_scheduled? + return false unless application.last_update_started_at + + application.last_update_started_at.utc >= Time.now.utc - BACKOFF_DELAY + end + end + end +end |