ae4966f29a
As Auto DevOps deployments both label and annotations, that will be included in the deploy board so need to warn at all.
155 lines
4.5 KiB
Ruby
155 lines
4.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
# Helper methods to do with Kubernetes network services & resources
|
|
module Kubernetes
|
|
def self.build_header_hash
|
|
Hash.new { |h, k| h[k] = [] }
|
|
end
|
|
|
|
# This is the comand that is run to start a terminal session. Kubernetes
|
|
# expects `command=foo&command=bar, not `command[]=foo&command[]=bar`
|
|
EXEC_COMMAND = URI.encode_www_form(
|
|
['sh', '-c', 'bash || sh'].map { |value| ['command', value] }
|
|
)
|
|
|
|
# Filters an array of pods (as returned by the kubernetes API) by their labels
|
|
def filter_by_label(items, labels = {})
|
|
items.select do |item|
|
|
metadata = item.fetch("metadata", {})
|
|
item_labels = metadata.fetch("labels", nil)
|
|
next unless item_labels
|
|
|
|
labels.all? { |k, v| item_labels[k.to_s] == v }
|
|
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)
|
|
filter_by_annotation(items, {
|
|
'app.gitlab.com/app' => app,
|
|
'app.gitlab.com/env' => env
|
|
})
|
|
end
|
|
|
|
def filter_by_legacy_label(items, app, env)
|
|
legacy_items = filter_by_label(items, { app: env })
|
|
|
|
non_legacy_items = filter_by_project_environment(legacy_items, app, env)
|
|
|
|
legacy_items - non_legacy_items
|
|
end
|
|
|
|
# Converts a pod (as returned by the kubernetes API) into a terminal
|
|
def terminals_for_pod(api_url, namespace, pod)
|
|
metadata = pod.fetch("metadata", {})
|
|
status = pod.fetch("status", {})
|
|
spec = pod.fetch("spec", {})
|
|
|
|
containers = spec["containers"]
|
|
pod_name = metadata["name"]
|
|
phase = status["phase"]
|
|
|
|
return unless containers.present? && pod_name.present? && phase == "Running"
|
|
|
|
created_at = DateTime.parse(metadata["creationTimestamp"]) rescue nil
|
|
|
|
containers.map do |container|
|
|
{
|
|
selectors: { pod: pod_name, container: container["name"] },
|
|
url: container_exec_url(api_url, namespace, pod_name, container["name"]),
|
|
subprotocols: ['channel.k8s.io'],
|
|
headers: ::Gitlab::Kubernetes.build_header_hash,
|
|
created_at: created_at
|
|
}
|
|
end
|
|
end
|
|
|
|
def add_terminal_auth(terminal, token:, max_session_time:, ca_pem: nil)
|
|
terminal[:headers] ||= ::Gitlab::Kubernetes.build_header_hash
|
|
terminal[:headers]['Authorization'] << "Bearer #{token}"
|
|
terminal[:max_session_time] = max_session_time
|
|
terminal[:ca_pem] = ca_pem if ca_pem.present?
|
|
end
|
|
|
|
def container_exec_url(api_url, namespace, pod_name, container_name)
|
|
url = URI.parse(api_url)
|
|
url.path = [
|
|
url.path.sub(%r{/+\z}, ''),
|
|
'api', 'v1',
|
|
'namespaces', ERB::Util.url_encode(namespace),
|
|
'pods', ERB::Util.url_encode(pod_name),
|
|
'exec'
|
|
].join('/')
|
|
|
|
url.query = {
|
|
container: container_name,
|
|
tty: true,
|
|
stdin: true,
|
|
stdout: true,
|
|
stderr: true
|
|
}.to_query + '&' + EXEC_COMMAND
|
|
|
|
case url.scheme
|
|
when 'http'
|
|
url.scheme = 'ws'
|
|
when 'https'
|
|
url.scheme = 'wss'
|
|
end
|
|
|
|
url.to_s
|
|
end
|
|
|
|
def to_kubeconfig(url:, namespace:, token:, ca_pem: nil)
|
|
return unless token.present?
|
|
|
|
config = {
|
|
apiVersion: 'v1',
|
|
clusters: [
|
|
name: 'gitlab-deploy',
|
|
cluster: {
|
|
server: url
|
|
}
|
|
],
|
|
contexts: [
|
|
name: 'gitlab-deploy',
|
|
context: {
|
|
cluster: 'gitlab-deploy',
|
|
namespace: namespace,
|
|
user: 'gitlab-deploy'
|
|
}
|
|
],
|
|
'current-context': 'gitlab-deploy',
|
|
kind: 'Config',
|
|
users: [
|
|
{
|
|
name: 'gitlab-deploy',
|
|
user: { token: token }
|
|
}
|
|
]
|
|
}
|
|
|
|
kubeconfig_embed_ca_pem(config, ca_pem) if ca_pem
|
|
|
|
YAML.dump(config.deep_stringify_keys)
|
|
end
|
|
|
|
private
|
|
|
|
def kubeconfig_embed_ca_pem(config, ca_pem)
|
|
cluster = config.dig(:clusters, 0, :cluster)
|
|
cluster[:'certificate-authority-data'] = Base64.strict_encode64(ca_pem)
|
|
end
|
|
end
|
|
end
|