Commit fad05a60 authored by James Fargher's avatar James Fargher Committed by Rémy Coutable

Update dashboards to additionally use new environment selector

Deploy boards now will check for app.gitlab.com/env and
app.gitlab.com/app
parent 22b215aa
...@@ -110,7 +110,7 @@ module Clusters ...@@ -110,7 +110,7 @@ module Clusters
# short time later # short time later
def terminals(environment) def terminals(environment)
with_reactive_cache do |data| with_reactive_cache do |data|
pods = filter_by_label(data[:pods], app: environment.slug) pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug)
terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }.compact terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }.compact
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) } terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end end
......
...@@ -131,8 +131,8 @@ class KubernetesService < DeploymentService ...@@ -131,8 +131,8 @@ class KubernetesService < DeploymentService
# short time later # short time later
def terminals(environment) def terminals(environment)
with_reactive_cache do |data| with_reactive_cache do |data|
pods = filter_by_label(data[:pods], app: environment.slug) pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug)
terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) } terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }.compact
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) } terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end end
end end
......
---
title: Update deploy boards to additionally select on "app.gitlab.com" annotations
merge_request: 25623
author:
type: changed
...@@ -73,15 +73,21 @@ To display the Deploy Boards for a specific [environment] you should: ...@@ -73,15 +73,21 @@ To display the Deploy Boards for a specific [environment] you should:
1. Configure the [Kubernetes service][kube-service] in your project for the 1. Configure the [Kubernetes service][kube-service] in your project for the
cluster. The Kubernetes namespace is of particular note as you will need it cluster. The Kubernetes namespace is of particular note as you will need it
for your deployment scripts (exposed by the `KUBE_NAMESPACE` env variable). for your deployment scripts (exposed by the `KUBE_NAMESPACE` env variable).
1. Ensure a Kubernetes label of `app: $CI_ENVIRONMENT_SLUG` is applied to the 1. Ensure Kubernetes annotations of `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG`
deployments, replica sets, and pods, where `$CI_ENVIRONMENT_SLUG` the value and `app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` are applied to the
of the CI variable. This is so we can lookup the proper environment in a deployments, replica sets, and pods, where `$CI_ENVIRONMENT_SLUG` and
cluster/namespace which may have more than one. These resources should be `$CI_PROJECT_PATH_SLUG` are the values of the CI variables. This is so we can
contained in the namespace defined in the Kubernetes service setting. lookup the proper environment in a cluster/namespace which may have more
You can use an [Autodeploy] `.gitlab-ci.yml` template which has predefined than one. These resources should be contained in the namespace defined in
stages and commands to use, and automatically applies the labeling. the Kubernetes service setting. You can use an [Autodeploy] `.gitlab-ci.yml`
Each project will need to have a unique namespace in Kubernetes as well. template which has predefined stages and commands to use, and automatically
The image below demonstrates how this is shown inside Kubernetes. applies the annotations. Each project will need to have a unique namespace in
Kubernetes as well. The image below demonstrates how this is shown inside
Kubernetes.
NOTE: **Note:**
The Kubernetes label of `app` is deprecated and will not be used for deploy
boards in the future.
![Deploy Boards Kubernetes Label](img/deploy_boards_kubernetes_label.png) ![Deploy Boards Kubernetes Label](img/deploy_boards_kubernetes_label.png)
......
...@@ -8,8 +8,8 @@ module EE ...@@ -8,8 +8,8 @@ module EE
def rollout_status(environment) def rollout_status(environment)
result = with_reactive_cache do |data| result = with_reactive_cache do |data|
deployments = filter_by_label(data[:deployments], app: environment.slug) deployments = filter_by_project_environment(data[:deployments], project.full_path_slug, environment.slug)
pods = filter_by_label(data[:pods], app: environment.slug) if data[:pods]&.any? pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) if data[:pods]&.any?
::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods: pods) ::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods: pods)
end end
......
...@@ -20,6 +20,10 @@ module Gitlab ...@@ -20,6 +20,10 @@ module Gitlab
metadata.fetch('labels', {}) metadata.fetch('labels', {})
end end
def annotations
metadata.fetch('annotations', {})
end
def track def track
labels.fetch('track', STABLE_TRACK_VALUE) labels.fetch('track', STABLE_TRACK_VALUE)
end end
......
...@@ -13,17 +13,24 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching: ...@@ -13,17 +13,24 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching:
subject(:rollout_status) { service.rollout_status(environment) } subject(:rollout_status) { service.rollout_status(environment) }
context 'with valid deployments' do context 'with valid deployments' do
let(:matched_deployment) { kube_deployment(environment_slug: environment.slug, project_slug: project.full_path_slug) }
let(:unmatched_deployment) { kube_deployment }
let(:matched_pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) }
let(:unmatched_pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: 'Pending') }
before do before do
stub_reactive_cache( stub_reactive_cache(
service, service,
deployments: [kube_deployment(app: environment.slug), kube_deployment], deployments: [matched_deployment, unmatched_deployment],
pods: [kube_pod(app: environment.slug), kube_pod(app: environment.slug, status: 'Pending')] pods: [matched_pod, unmatched_pod]
) )
end end
it 'creates a matching RolloutStatus' do it 'creates a matching RolloutStatus' do
expect(rollout_status).to be_kind_of(::Gitlab::Kubernetes::RolloutStatus) expect(rollout_status).to be_kind_of(::Gitlab::Kubernetes::RolloutStatus)
expect(rollout_status.deployments.map(&:labels)).to eq([{ 'app' => 'env-000000' }]) expect(rollout_status.deployments.map(&:annotations)).to eq([
{ 'app.gitlab.com/app' => project.full_path_slug, 'app.gitlab.com/env' => 'env-000000' }
])
end end
end end
......
...@@ -697,6 +697,8 @@ rollout 100%: ...@@ -697,6 +697,8 @@ rollout 100%:
helm upgrade --install \ helm upgrade --install \
--wait \ --wait \
--set service.enabled="$service_enabled" \ --set service.enabled="$service_enabled" \
--set gitlab.app="$CI_PROJECT_PATH_SLUG" \
--set gitlab.env="$CI_ENVIRONMENT_SLUG" \
--set releaseOverride="$CI_ENVIRONMENT_SLUG" \ --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
--set image.repository="$CI_APPLICATION_REPOSITORY" \ --set image.repository="$CI_APPLICATION_REPOSITORY" \
--set image.tag="$CI_APPLICATION_TAG" \ --set image.tag="$CI_APPLICATION_TAG" \
...@@ -734,6 +736,8 @@ rollout 100%: ...@@ -734,6 +736,8 @@ rollout 100%:
helm upgrade --install \ helm upgrade --install \
--wait \ --wait \
--set service.enabled="$service_enabled" \ --set service.enabled="$service_enabled" \
--set gitlab.app="$CI_PROJECT_PATH_SLUG" \
--set gitlab.env="$CI_ENVIRONMENT_SLUG" \
--set releaseOverride="$CI_ENVIRONMENT_SLUG" \ --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
--set image.repository="$CI_APPLICATION_REPOSITORY" \ --set image.repository="$CI_APPLICATION_REPOSITORY" \
--set image.tag="$CI_APPLICATION_TAG" \ --set image.tag="$CI_APPLICATION_TAG" \
......
...@@ -24,6 +24,30 @@ module Gitlab ...@@ -24,6 +24,30 @@ module Gitlab
end end
end end
# Filters an array of pods (as returned by the kubernetes API) by their annotations
def filter_by_annotation(items, annotations = {})
items.select do |item|
metadata = item.fetch("metadata", {})
item_annotations = metadata.fetch("annotations", nil)
next unless item_annotations
annotations.all? { |k, v| item_annotations[k.to_s] == v }
end
end
# Filters an array of pods (as returned by the kubernetes API) by their project and environment
def filter_by_project_environment(items, app, env)
pods = filter_by_annotation(items, {
'app.gitlab.com/app' => app,
'app.gitlab.com/env' => env
})
return pods unless pods.empty?
filter_by_label(items, {
'app' => env, # deprecated: replaced by app.gitlab.com/env
})
end
# Converts a pod (as returned by the kubernetes API) into a terminal # Converts a pod (as returned by the kubernetes API) into a terminal
def terminals_for_pod(api_url, namespace, pod) def terminals_for_pod(api_url, namespace, pod)
metadata = pod.fetch("metadata", {}) metadata = pod.fetch("metadata", {})
......
...@@ -40,10 +40,40 @@ describe Gitlab::Kubernetes do ...@@ -40,10 +40,40 @@ describe Gitlab::Kubernetes do
describe '#filter_by_label' do describe '#filter_by_label' do
it 'returns matching labels' do it 'returns matching labels' do
matching_items = [kube_pod(app: 'foo'), kube_deployment(app: 'foo')] matching_items = [kube_pod(track: 'foo'), kube_deployment(track: 'foo')]
items = matching_items + [kube_pod, kube_deployment] items = matching_items + [kube_pod, kube_deployment]
expect(filter_by_label(items, app: 'foo')).to eq(matching_items) expect(filter_by_label(items, 'track' => 'foo')).to eq(matching_items)
end
end
describe '#filter_by_annotation' do
it 'returns matching labels' do
matching_items = [kube_pod(environment_slug: 'foo'), kube_deployment(environment_slug: 'foo')]
items = matching_items + [kube_pod, kube_deployment]
expect(filter_by_annotation(items, 'app.gitlab.com/env' => 'foo')).to eq(matching_items)
end
end
describe '#filter_by_project_environment' do
let(:matching_pod) { kube_pod(environment_slug: 'production', project_slug: 'my-cool-app') }
it 'returns matching legacy env label' do
matching_pod['metadata']['annotations'].delete('app.gitlab.com/app')
matching_pod['metadata']['annotations'].delete('app.gitlab.com/env')
matching_pod['metadata']['labels']['app'] = 'production'
matching_items = [matching_pod]
items = matching_items + [kube_pod]
expect(filter_by_project_environment(items, 'my-cool-app', 'production')).to eq(matching_items)
end
it 'returns matching env label' do
matching_items = [matching_pod]
items = matching_items + [kube_pod]
expect(filter_by_project_environment(items, 'my-cool-app', 'production')).to eq(matching_items)
end end
end end
......
...@@ -375,14 +375,14 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching ...@@ -375,14 +375,14 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end end
context 'with valid pods' do context 'with valid pods' do
let(:pod) { kube_pod(app: environment.slug) } let(:pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) }
let(:pod_with_no_terminal) { kube_pod(app: environment.slug, status: "Pending") } let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") }
let(:terminals) { kube_terminals(service, pod) } let(:terminals) { kube_terminals(service, pod) }
before do before do
stub_reactive_cache( stub_reactive_cache(
service, service,
pods: [pod, pod, pod_with_no_terminal, kube_pod(app: "should-be-filtered-out")] pods: [pod, pod, pod_with_no_terminal, kube_pod(environment_slug: "should-be-filtered-out")]
) )
end end
......
...@@ -323,13 +323,14 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do ...@@ -323,13 +323,14 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end end
context 'with valid pods' do context 'with valid pods' do
let(:pod) { kube_pod(app: environment.slug) } let(:pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) }
let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") }
let(:terminals) { kube_terminals(service, pod) } let(:terminals) { kube_terminals(service, pod) }
before do before do
stub_reactive_cache( stub_reactive_cache(
service, service,
pods: [pod, pod, kube_pod(app: "should-be-filtered-out")] pods: [pod, pod, pod_with_no_terminal, kube_pod(environment_slug: "should-be-filtered-out")]
) )
end end
......
...@@ -250,16 +250,19 @@ module KubernetesHelpers ...@@ -250,16 +250,19 @@ module KubernetesHelpers
# This is a partial response, it will have many more elements in reality but # This is a partial response, it will have many more elements in reality but
# these are the ones we care about at the moment # these are the ones we care about at the moment
def kube_pod(name: "kube-pod", app: "valid-pod-label", status: "Running", track: nil) def kube_pod(name: "kube-pod", environment_slug: "production", project_slug: "project-path-slug", status: "Running", track: nil)
{ {
"metadata" => { "metadata" => {
"name" => name, "name" => name,
"generate_name" => "generated-name-with-suffix", "generate_name" => "generated-name-with-suffix",
"creationTimestamp" => "2016-11-25T19:55:19Z", "creationTimestamp" => "2016-11-25T19:55:19Z",
"annotations" => {
"app.gitlab.com/env" => environment_slug,
"app.gitlab.com/app" => project_slug
},
"labels" => { "labels" => {
"app" => app,
"track" => track "track" => track
} }.compact
}, },
"spec" => { "spec" => {
"containers" => [ "containers" => [
...@@ -293,13 +296,16 @@ module KubernetesHelpers ...@@ -293,13 +296,16 @@ module KubernetesHelpers
} }
end end
def kube_deployment(name: "kube-deployment", app: "valid-deployment-label", track: nil) def kube_deployment(name: "kube-deployment", environment_slug: "production", project_slug: "project-path-slug", track: nil)
{ {
"metadata" => { "metadata" => {
"name" => name, "name" => name,
"generation" => 4, "generation" => 4,
"annotations" => {
"app.gitlab.com/env" => environment_slug,
"app.gitlab.com/app" => project_slug
},
"labels" => { "labels" => {
"app" => app,
"track" => track "track" => track
}.compact }.compact
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment