diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /lib/gitlab/kubernetes | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'lib/gitlab/kubernetes')
-rw-r--r-- | lib/gitlab/kubernetes/deployment.rb | 117 | ||||
-rw-r--r-- | lib/gitlab/kubernetes/helm/v2/client_command.rb | 11 | ||||
-rw-r--r-- | lib/gitlab/kubernetes/helm/v2/reset_command.rb | 26 | ||||
-rw-r--r-- | lib/gitlab/kubernetes/ingress.rb | 46 | ||||
-rw-r--r-- | lib/gitlab/kubernetes/rollout_instances.rb | 75 | ||||
-rw-r--r-- | lib/gitlab/kubernetes/rollout_status.rb | 72 |
6 files changed, 313 insertions, 34 deletions
diff --git a/lib/gitlab/kubernetes/deployment.rb b/lib/gitlab/kubernetes/deployment.rb new file mode 100644 index 00000000000..55ed9a7517e --- /dev/null +++ b/lib/gitlab/kubernetes/deployment.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + class Deployment + include Gitlab::Utils::StrongMemoize + + STABLE_TRACK_VALUE = 'stable'.freeze + + def initialize(attributes = {}, pods: []) + @attributes = attributes + @pods = pods + end + + def name + metadata['name'] || 'unknown' + end + + def labels + metadata.fetch('labels', {}) + end + + def annotations + metadata.fetch('annotations', {}) + end + + def track + labels.fetch('track', STABLE_TRACK_VALUE) + end + + def stable? + track == 'stable' + end + + def order + stable? ? 1 : 0 + end + + def outdated? + observed_generation < generation + end + + def wanted_instances + spec.fetch('replicas', 0) + end + + def created_instances + filtered_pods_by_track.map do |pod| + pod_metadata = pod.fetch('metadata', {}) + pod_name = pod_metadata['name'] || pod_metadata['generateName'] + pod_status = pod.dig('status', 'phase') + + deployment_instance(pod_name: pod_name, pod_status: pod_status) + end + end + + # These are replicas that did not get created yet, + # So they still do not have any associated pod, + # these are marked as pending instances. + def not_created_instances + pending_instances_count = wanted_instances - filtered_pods_by_track.count + + return [] if pending_instances_count <= 0 + + Array.new(pending_instances_count, deployment_instance(pod_name: 'Not provided', pod_status: 'Pending')) + end + + def filtered_pods_by_track + strong_memoize(:filtered_pods_by_track) do + @pods.select { |pod| has_same_track?(pod) } + end + end + + def instances + created_instances + not_created_instances + end + + private + + def deployment_instance(pod_name:, pod_status:) + { + status: pod_status&.downcase, + pod_name: pod_name, + tooltip: "#{pod_name} (#{pod_status})", + track: track, + stable: stable? + } + end + + def has_same_track?(pod) + pod_track = pod.dig('metadata', 'labels', 'track') || STABLE_TRACK_VALUE + + pod_track == track + end + + def metadata + @attributes.fetch('metadata', {}) + end + + def spec + @attributes.fetch('spec', {}) + end + + def status + @attributes.fetch('status', {}) + end + + def generation + metadata.fetch('generation', 0) + end + + def observed_generation + status.fetch('observedGeneration', 0) + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/client_command.rb b/lib/gitlab/kubernetes/helm/v2/client_command.rb index 88693a28d6c..8b15af9aeea 100644 --- a/lib/gitlab/kubernetes/helm/v2/client_command.rb +++ b/lib/gitlab/kubernetes/helm/v2/client_command.rb @@ -22,17 +22,6 @@ module Gitlab def repository_update_command 'helm repo update' end - - def optional_tls_flags - return [] unless files.key?(:'ca.pem') - - [ - '--tls', - '--tls-ca-cert', "#{files_dir}/ca.pem", - '--tls-cert', "#{files_dir}/cert.pem", - '--tls-key', "#{files_dir}/key.pem" - ] - end end end end diff --git a/lib/gitlab/kubernetes/helm/v2/reset_command.rb b/lib/gitlab/kubernetes/helm/v2/reset_command.rb index 172a0884c49..00626501a9a 100644 --- a/lib/gitlab/kubernetes/helm/v2/reset_command.rb +++ b/lib/gitlab/kubernetes/helm/v2/reset_command.rb @@ -9,9 +9,8 @@ module Gitlab def generate_script super + [ - reset_helm_command, - delete_tiller_replicaset, - delete_tiller_clusterrolebinding + init_command, + reset_helm_command ].join("\n") end @@ -21,27 +20,8 @@ module Gitlab private - # This method can be delete once we upgrade Helm to > 12.13.0 - # https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/27096#note_159695900 - # - # Tracking this method to be removed here: - # https://gitlab.com/gitlab-org/gitlab-foss/issues/52791#note_199374155 - def delete_tiller_replicaset - delete_args = %w[replicaset -n gitlab-managed-apps -l name=tiller] - - Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) - end - - def delete_tiller_clusterrolebinding - delete_args = %w[clusterrolebinding tiller-admin] - - Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) - end - def reset_helm_command - command = %w[helm reset] + optional_tls_flags - - command.shelljoin + 'helm reset --force' end end end diff --git a/lib/gitlab/kubernetes/ingress.rb b/lib/gitlab/kubernetes/ingress.rb new file mode 100644 index 00000000000..c5643dd670a --- /dev/null +++ b/lib/gitlab/kubernetes/ingress.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + class Ingress + include Gitlab::Utils::StrongMemoize + + # Canary Ingress Annotations https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary + ANNOTATION_KEY_CANARY = 'nginx.ingress.kubernetes.io/canary' + ANNOTATION_KEY_CANARY_WEIGHT = 'nginx.ingress.kubernetes.io/canary-weight' + + def initialize(attributes = {}) + @attributes = attributes + end + + def canary? + strong_memoize(:is_canary) do + annotations.any? do |key, value| + key == ANNOTATION_KEY_CANARY && value == 'true' + end + end + end + + def canary_weight + return unless canary? + return unless annotations.key?(ANNOTATION_KEY_CANARY_WEIGHT) + + annotations[ANNOTATION_KEY_CANARY_WEIGHT].to_i + end + + def name + metadata['name'] + end + + private + + def metadata + @attributes.fetch('metadata', {}) + end + + def annotations + metadata.fetch('annotations', {}) + end + end + end +end diff --git a/lib/gitlab/kubernetes/rollout_instances.rb b/lib/gitlab/kubernetes/rollout_instances.rb new file mode 100644 index 00000000000..c5dba71f505 --- /dev/null +++ b/lib/gitlab/kubernetes/rollout_instances.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + class RolloutInstances + include ::Gitlab::Utils::StrongMemoize + + def initialize(deployments, pods) + @deployments = deployments + @pods = pods + end + + def pod_instances + pods = matching_pods + extra_pending_pods + + pods.sort_by(&:order).map do |pod| + to_hash(pod) + end + end + + private + + attr_reader :deployments, :pods + + def matching_pods + strong_memoize(:matching_pods) do + deployment_tracks = deployments.map(&:track) + pods.select { |p| deployment_tracks.include?(p.track) } + end + end + + def extra_pending_pods + wanted_instances = sum_hashes(deployments.map { |d| { d.track => d.wanted_instances } }) + present_instances = sum_hashes(matching_pods.map { |p| { p.track => 1 } }) + pending_instances = subtract_hashes(wanted_instances, present_instances) + + pending_instances.flat_map do |track, num| + Array.new(num, pending_pod_for(track)) + end + end + + def sum_hashes(hashes) + hashes.reduce({}) do |memo, hash| + memo.merge(hash) { |_key, memo_val, hash_val| memo_val + hash_val } + end + end + + def subtract_hashes(hash_a, hash_b) + hash_a.merge(hash_b) { |_key, val_a, val_b| [0, val_a - val_b].max } + end + + def pending_pod_for(track) + ::Gitlab::Kubernetes::Pod.new({ + 'status' => { 'phase' => 'Pending' }, + 'metadata' => { + 'name' => 'Not provided', + 'labels' => { + 'track' => track + } + } + }) + end + + def to_hash(pod) + { + status: pod.status&.downcase, + pod_name: pod.name, + tooltip: "#{pod.name} (#{pod.status})", + track: pod.track, + stable: pod.stable? + } + end + end + end +end diff --git a/lib/gitlab/kubernetes/rollout_status.rb b/lib/gitlab/kubernetes/rollout_status.rb new file mode 100644 index 00000000000..e275303e650 --- /dev/null +++ b/lib/gitlab/kubernetes/rollout_status.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + # Calculates the rollout status for a set of kubernetes deployments. + # + # A GitLab environment may be composed of several Kubernetes deployments and + # other resources. The rollout status sums the Kubernetes deployments + # together. + class RolloutStatus + attr_reader :deployments, :instances, :completion, :status, :canary_ingress + + def complete? + completion == 100 + end + + def loading? + @status == :loading + end + + def not_found? + @status == :not_found + end + + def found? + @status == :found + end + + def canary_ingress_exists? + canary_ingress.present? + end + + def self.from_deployments(*deployments_attrs, pods_attrs: [], ingresses: []) + return new([], status: :not_found) if deployments_attrs.empty? + + deployments = deployments_attrs.map do |attrs| + ::Gitlab::Kubernetes::Deployment.new(attrs, pods: pods_attrs) + end + deployments.sort_by!(&:order) + + pods = pods_attrs.map do |attrs| + ::Gitlab::Kubernetes::Pod.new(attrs) + end + + ingresses = ingresses.map { |ingress| ::Gitlab::Kubernetes::Ingress.new(ingress) } + + new(deployments, pods: pods, ingresses: ingresses) + end + + def self.loading + new([], status: :loading) + end + + def initialize(deployments, pods: [], ingresses: [], status: :found) + @status = status + @deployments = deployments + @instances = RolloutInstances.new(deployments, pods).pod_instances + @canary_ingress = ingresses.find(&:canary?) + + @completion = + if @instances.empty? + 100 + else + # We downcase the pod status in Gitlab::Kubernetes::Deployment#deployment_instance + finished = @instances.count { |instance| instance[:status] == ::Gitlab::Kubernetes::Pod::RUNNING.downcase } + + (finished / @instances.count.to_f * 100).to_i + end + end + end + end +end |