Commit 7eed947b authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch '1589-deploy-boards-backend' into 'master'

Deploy boards backend

Closes #1589

See merge request !1278
parents b33310fa dee466ae
......@@ -5,7 +5,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :authorize_create_deployment!, only: [:stop]
before_action :authorize_update_environment!, only: [:edit, :update]
before_action :authorize_admin_environment!, only: [:terminal, :terminal_websocket_authorize]
before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize]
before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :status]
before_action :verify_api_request!, only: :terminal_websocket_authorize
def index
......@@ -109,6 +109,23 @@ class Projects::EnvironmentsController < Projects::ApplicationController
end
end
# The rollout status of an enviroment
def status
unless @environment.deployment_service_ready?
render text: 'Not found', status: 404
return
end
rollout_status = @environment.rollout_status
if rollout_status.nil?
render body: nil, status: 204 # no result yet
else
serializer = RolloutStatusSerializer.new(project: @project, user: @current_user)
render json: serializer.represent(rollout_status)
end
end
private
def verify_api_request!
......
......@@ -137,12 +137,16 @@ class Environment < ActiveRecord::Base
end
end
def has_terminals?
def deployment_service_ready?
project.deployment_service.present? && available? && last_deployment.present?
end
def terminals
project.deployment_service.terminals(self) if has_terminals?
project.deployment_service.terminals(self) if deployment_service_ready?
end
def rollout_status
project.deployment_service.rollout_status(self) if deployment_service_ready?
end
# An environment name is not necessarily suitable for use in URLs, DNS
......
......@@ -30,4 +30,10 @@ class DeploymentService < Service
def terminals(environment)
raise NotImplementedError
end
# Environments have a rollout status. This represents the current state of
# deployments to that environment.
def rollout_status(environment)
raise NotImplementedError
end
end
......@@ -104,30 +104,27 @@ class KubernetesService < DeploymentService
# short time later
def terminals(environment)
with_reactive_cache do |data|
pods = data.fetch(:pods, nil)
filter_pods(pods, app: environment.slug).
flat_map { |pod| terminals_for_pod(api_url, namespace, pod) }.
each { |terminal| add_terminal_auth(terminal, terminal_auth) }
pods = filter_by_label(data[:pods], app: environment.slug)
terminals = pods.flat_map { |pod| terminals_for_pod(api_url, namespace, pod) }
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end
end
# Caches all pods in the namespace so other calls don't need to block on
# network access.
def calculate_reactive_cache
return unless active? && project && !project.pending_delete?
kubeclient = build_kubeclient!
def rollout_status(environment)
with_reactive_cache do |data|
specs = filter_by_label(data[:deployments], app: environment.slug)
# Store as hashes, rather than as third-party types
pods = begin
kubeclient.get_pods(namespace: namespace).as_json
rescue KubeException => err
raise err unless err.error_code == 404
[]
::Gitlab::Kubernetes::RolloutStatus.from_specs(*specs)
end
end
# Caches all pods & deployments in the namespace so other calls don't need to
# block on network access.
def calculate_reactive_cache
return unless active? && project && !project.pending_delete?
# We may want to cache extra things in the future
{ pods: pods }
{ pods: read_pods, deployments: read_deployments }
end
private
......@@ -144,6 +141,25 @@ class KubernetesService < DeploymentService
)
end
# Returns a hash of all pods in the namespace
def read_pods
kubeclient = build_kubeclient!
kubeclient.get_pods(namespace: namespace).as_json
rescue KubeException => err
raise err unless err.error_code == 404
[]
end
def read_deployments
kubeclient = build_kubeclient!(api_path: 'apis/extensions', api_version: 'v1beta1')
kubeclient.get_deployments(namespace: namespace).as_json
rescue KubeException => err
raise err unless err.error_code == 404
[]
end
def kubeclient_ssl_options
opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
......@@ -159,11 +175,11 @@ class KubernetesService < DeploymentService
{ bearer_token: token }
end
def join_api_url(*parts)
def join_api_url(api_path)
url = URI.parse(api_url)
prefix = url.path.sub(%r{/+\z}, '')
url.path = [prefix, *parts].join("/")
url.path = [prefix, api_path].join("/")
url.to_s
end
......
......@@ -23,7 +23,7 @@ class EnvironmentEntity < Grape::Entity
environment)
end
expose :terminal_path, if: ->(environment, _) { environment.has_terminals? } do |environment|
expose :terminal_path, if: ->(environment, _) { environment.deployment_service_ready? } do |environment|
can?(request.user, :admin_environment, environment.project) &&
terminal_namespace_project_environment_path(
environment.project.namespace,
......@@ -31,5 +31,13 @@ class EnvironmentEntity < Grape::Entity
environment)
end
expose :rollout_status_path, if: ->(environment, _) { environment.deployment_service_ready? } do |environment|
status_namespace_project_environment_path(
environment.project.namespace,
environment.project,
environment,
format: :json)
end
expose :created_at, :updated_at
end
class RolloutStatusEntity < Grape::Entity
include RequestAwareEntity
expose :instances
expose :completion
expose :is_completed do |rollout_status|
rollout_status.complete?
end
end
class RolloutStatusSerializer < BaseSerializer
entity RolloutStatusEntity
end
- if environment.has_terminals? && can?(current_user, :admin_environment, @project)
- if environment.deployment_service_ready? && can?(current_user, :admin_environment, @project)
= link_to terminal_namespace_project_environment_path(@project.namespace, @project, environment), class: 'btn terminal-button' do
= icon('terminal')
---
title: Deploy board backend
merge_request: 1278
author:
......@@ -191,6 +191,7 @@ constraints(ProjectUrlConstrainer.new) do
member do
post :stop
get :terminal
get :status, constraints: { format: :json }
get '/terminal.ws/authorize', to: 'environments#terminal_websocket_authorize', constraints: { format: nil }
end
......
......@@ -8,13 +8,13 @@ module Gitlab
)
# Filters an array of pods (as returned by the kubernetes API) by their labels
def filter_pods(pods, labels = {})
pods.select do |pod|
metadata = pod.fetch("metadata", {})
pod_labels = metadata.fetch("labels", nil)
next unless pod_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| pod_labels[k.to_s] == v }
labels.all? { |k, v| item_labels[k.to_s] == v }
end
end
......
module Gitlab
module Kubernetes
class Deployment
def initialize(attributes = {})
@attributes = attributes
end
def name
metadata['name']
end
def labels
metadata['labels']
end
def outdated?
observed_generation < generation
end
def wanted_replicas
spec.fetch('replicas', 0)
end
def finished_replicas
status.fetch('availableReplicas', 0)
end
def deploying_replicas
updated_replicas - finished_replicas
end
def waiting_replicas
wanted_replicas - updated_replicas
end
def instances
return deployment_instances(wanted_replicas, 'unknown', 'waiting') if name.nil?
return deployment_instances(wanted_replicas, name, 'waiting') if outdated?
out = deployment_instances(finished_replicas, name, 'finished')
out.push(*deployment_instances(deploying_replicas, name, 'deploying', out.size))
out.push(*deployment_instances(waiting_replicas, name, 'waiting', out.size))
out
end
private
def deployment_instances(n, name, status, offset = 0)
return [] if n < 0
Array.new(n) { |idx| deployment_instance(idx + offset, name, status) }
end
def deployment_instance(n, name, status)
{ status: status, tooltip: "#{name} (pod #{n}) #{status.capitalize}" }
end
def metadata
@attributes.fetch('metadata', {})
end
def spec
@attributes.fetch('spec', {})
end
def status
@attributes.fetch('status', {})
end
def updated_replicas
status.fetch('updatedReplicas', 0)
end
def generation
metadata.fetch('generation', 0)
end
def observed_generation
status.fetch('observedGeneration', 0)
end
end
end
end
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, unified by an `app=` label. The rollout status sums the
# Kubernetes deployments together.
class RolloutStatus
attr_reader :deployments, :instances, :completion
def complete?
completion == 100
end
def self.from_specs(*specs)
deployments = specs.map { |spec| ::Gitlab::Kubernetes::Deployment.new(spec) }
new(deployments)
end
def initialize(deployments)
@deployments = deployments
@instances = deployments.flat_map(&:instances)
@completion =
if @instances.empty?
100
else
finished = @instances.select {|instance| instance[:status] == 'finished' }.count
(finished / @instances.count.to_f * 100).to_i
end
end
end
end
end
......@@ -187,6 +187,44 @@ describe Projects::EnvironmentsController do
end
end
describe 'GET #status' do
context 'without deployment service' do
it 'returns 404' do
get :status, environment_params
expect(response.status).to eq(404)
end
end
context 'with deployment service' do
let(:project) { create(:kubernetes_project) }
before do
allow_any_instance_of(Environment).to receive(:deployment_service_ready?).and_return(true)
end
it 'returns 204 until the rollout status is present' do
expect_any_instance_of(Environment).
to receive(:rollout_status).
and_return(nil)
get :status, environment_params
expect(response.status).to eq(204)
end
it 'returns the rollout status when present' do
expect_any_instance_of(Environment).
to receive(:rollout_status).
and_return(::Gitlab::Kubernetes::RolloutStatus.new([]))
get :status, environment_params
expect(response.status).to eq(200)
end
end
end
def environment_params(opts = {})
opts.reverse_merge(namespace_id: project.namespace,
project_id: project,
......
require 'spec_helper'
describe Gitlab::Kubernetes::Deployment do
subject(:deployment) { described_class.new(params) }
describe '#name' do
let(:params) { named(:selected) }
it { expect(deployment.name).to eq(:selected) }
end
describe '#labels' do
let(:params) { make('metadata', 'labels' => :selected) }
it { expect(deployment.labels).to eq(:selected) }
end
describe '#outdated?' do
context 'when outdated' do
let(:params) { generation(2, 1) }
it { expect(deployment.outdated?).to be_truthy }
end
context 'when up to date' do
let(:params) { generation(2, 2) }
it { expect(deployment.outdated?).to be_falsy }
end
context 'when ahead of latest' do
let(:params) { generation(1, 2) }
it { expect(deployment.outdated?).to be_falsy }
end
end
describe '#wanted_replicas' do
let(:params) { make('spec', 'replicas' => :selected ) }
it { expect(deployment.wanted_replicas).to eq(:selected) }
end
describe '#finished_replicas' do
let(:params) { make('status', 'availableReplicas' => :selected) }
it { expect(deployment.finished_replicas).to eq(:selected) }
end
describe '#deploying_replicas' do
let(:params) { make('status', 'availableReplicas' => 2, 'updatedReplicas' => 4) }
it { expect(deployment.deploying_replicas).to eq(2) }
end
describe '#waiting_replicas' do
let(:params) { combine(make('spec', 'replicas' => 4), make('status', 'updatedReplicas' => 2)) }
it { expect(deployment.waiting_replicas).to eq(2) }
end
describe '#instances' do
context 'when unnamed' do
let(:params) { combine(generation(1, 1), instances) }
it 'returns all instances as unknown and waiting' do
expected = [
{ status: 'waiting', tooltip: 'unknown (pod 0) Waiting' },
{ status: 'waiting', tooltip: 'unknown (pod 1) Waiting' },
{ status: 'waiting', tooltip: 'unknown (pod 2) Waiting' },
{ status: 'waiting', tooltip: 'unknown (pod 3) Waiting' },
]
expect(deployment.instances).to eq(expected)
end
end
context 'when outdated' do
let(:params) { combine(named('foo'), generation(1, 0), instances) }
it 'returns all instances as named and waiting' do
expected = [
{ status: 'waiting', tooltip: 'foo (pod 0) Waiting' },
{ status: 'waiting', tooltip: 'foo (pod 1) Waiting' },
{ status: 'waiting', tooltip: 'foo (pod 2) Waiting' },
{ status: 'waiting', tooltip: 'foo (pod 3) Waiting' },
]
expect(deployment.instances).to eq(expected)
end
end
context 'with pods of each type' do
let(:params) { combine(named('foo'), generation(1, 1), instances) }
it 'returns all instances' do
expected = [
{ status: 'finished', tooltip: 'foo (pod 0) Finished' },
{ status: 'deploying', tooltip: 'foo (pod 1) Deploying' },
{ status: 'waiting', tooltip: 'foo (pod 2) Waiting' },
{ status: 'waiting', tooltip: 'foo (pod 3) Waiting' },
]
expect(deployment.instances).to eq(expected)
end
end
end
def generation(expected, observed)
combine(
make('metadata', 'generation' => expected),
make('status', 'observedGeneration' => observed)
)
end
def named(name = "foo")
make('metadata', 'name' => name)
end
def instances
combine(
make('spec', 'replicas' => 4),
make('status', 'availableReplicas' => 1, 'updatedReplicas' => 2),
)
end
def make(key, values = {})
hsh = {}
hsh[key] = values
hsh
end
def combine(*hashes)
out = {}
hashes.each { |hsh| out = out.deep_merge(hsh) }
out
end
end
require 'spec_helper'
describe Gitlab::Kubernetes::RolloutStatus do
include KubernetesHelpers
let(:specs_all_finished) { [kube_deployment(name: 'one'), kube_deployment(name: 'two')] }
let(:specs_half_finished) do
[
kube_deployment(name: 'one'),
kube_deployment(name: 'two').deep_merge('status' => { 'availableReplicas' => 0 })
]
end
let(:specs) { specs_all_finished }
subject(:rollout_status) { described_class.from_specs(*specs) }
describe '#deployments' do
it 'stores the deployments' do
expect(rollout_status.deployments).to be_kind_of(Array)
expect(rollout_status.deployments.size).to eq(2)
expect(rollout_status.deployments.first).to be_kind_of(::Gitlab::Kubernetes::Deployment)
end
end
describe '#instances' do
it 'stores the union of deployment instances' do
expected = [
{ status: 'finished', tooltip: 'one (pod 0) Finished' },
{ status: 'finished', tooltip: 'one (pod 1) Finished' },
{ status: 'finished', tooltip: 'one (pod 2) Finished' },
{ status: 'finished', tooltip: 'two (pod 0) Finished' },
{ status: 'finished', tooltip: 'two (pod 1) Finished' },
{ status: 'finished', tooltip: 'two (pod 2) Finished' },
]
expect(rollout_status.instances).to eq(expected)
end
end
describe '#completion' do
subject { rollout_status.completion }
context 'when all instances are finished' do
it { is_expected.to eq(100) }
end
context 'when half of the instances are finished' do
let(:specs) { specs_half_finished }
it { is_expected.to eq(50) }
end
end
describe '#complete?' do
subject { rollout_status.complete? }
context 'when all instances are finished' do
it { is_expected.to be_truthy }
end
context 'when half of the instances are finished' do
let(:specs) { specs_half_finished }
it { is_expected.to be_falsy}
end
end
end
require 'spec_helper'
describe Gitlab::Kubernetes do
include KubernetesHelpers
include described_class
describe '#container_exec_url' do
......@@ -36,4 +37,13 @@ describe Gitlab::Kubernetes do
it { expect(result.query).to match(/\Acontainer=container\+1&/) }
end
end
describe '#filter_by_label' do
it 'returns matching labels' do
matching_items = [kube_pod(app: 'foo'), kube_deployment(app: 'foo')]
items = matching_items + [kube_pod, kube_deployment]
expect(filter_by_label(items, app: 'foo')).to eq(matching_items)
end
end
end
......@@ -247,8 +247,8 @@ describe Environment, models: true do
end
end
describe '#has_terminals?' do
subject { environment.has_terminals? }
describe '#deployment_service_ready?' do
subject { environment.deployment_service_ready? }
context 'when the enviroment is available' do
context 'with a deployment service' do
......@@ -281,7 +281,7 @@ describe Environment, models: true do
subject { environment.terminals }
context 'when the environment has terminals' do
before { allow(environment).to receive(:has_terminals?).and_return(true) }
before { allow(environment).to receive(:deployment_service_ready?).and_return(true) }
it 'returns the terminals from the deployment service' do
expect(project.deployment_service).
......@@ -293,7 +293,29 @@ describe Environment, models: true do
end
context 'when the environment does not have terminals' do
before { allow(environment).to receive(:has_terminals?).and_return(false) }
before { allow(environment).to receive(:deployment_service_ready?).and_return(false) }
it { is_expected.to eq(nil) }
end
end
describe '#rollout_status' do
let(:project) { create(:kubernetes_project) }
subject { environment.rollout_status }
context 'when the environment has rollout status' do
before { allow(environment).to receive(:deployment_service_ready?).and_return(true) }
it 'returns the rollout status from the deployment service' do
expect(project.deployment_service).
to receive(:rollout_status).with(environment).
and_return(:fake_rollout_status)
is_expected.to eq(:fake_rollout_status)
end
end
context 'when the environment does not have rollout status' do
before { allow(environment).to receive(:deployment_service_ready?).and_return(false) }
it { is_expected.to eq(nil) }
end
end
......
......@@ -7,24 +7,6 @@ describe KubernetesService, models: true, caching: true do
let(:project) { create(:kubernetes_project) }
let(:service) { project.kubernetes_service }
# We use Kubeclient to interactive with the Kubernetes API. It will
# GET /api/v1 for a list of resources the API supports. This must be stubbed
# in addition to any other HTTP requests we expect it to perform.
let(:discovery_url) { service.api_url + '/api/v1' }
let(:discovery_response) { { body: kube_discovery_body.to_json } }
let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.namespace}/pods" }
let(:pods_response) { { body: kube_pods_body(kube_pod).to_json } }
def stub_kubeclient_discover
WebMock.stub_request(:get, discovery_url).to_return(discovery_response)
end
def stub_kubeclient_pods
stub_kubeclient_discover
WebMock.stub_request(:get, pods_url).to_return(pods_response)
end
describe "Associations" do
it { is_expected.to belong_to :project }
end
......@@ -87,6 +69,8 @@ describe KubernetesService, models: true, caching: true do
end
describe '#test' do
let(:discovery_url) { 'https://kubernetes.example.com/api/v1' }
before do
stub_kubeclient_discover
end
......@@ -95,7 +79,8 @@ describe KubernetesService, models: true, caching: true do
let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' }
it 'tests with the prefix' do
service.api_url = 'https://kubernetes.example.com/prefix/'
service.api_url = 'https://kubernetes.example.com/prefix'
stub_kubeclient_discover
expect(service.test[:success]).to be_truthy
expect(WebMock).to have_requested(:get, discovery_url).once
......@@ -123,9 +108,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'failure' do
let(:discovery_response) { { status: 404 } }
it 'fails to read the discovery endpoint' do
WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(status: 404)
expect(service.test[:success]).to be_falsy
expect(WebMock).to have_requested(:get, discovery_url).once
end
......@@ -201,8 +186,26 @@ describe KubernetesService, models: true, caching: true do
end
end
describe '#rollout_status' do
let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") }
subject(:rollout_status) { service.rollout_status(environment) }
context 'with valid deployments' do
before do
stub_reactive_cache(
service,
deployments: [kube_deployment(app: environment.slug), kube_deployment]
)
end
it 'creates a matching RolloutStatus' do
expect(rollout_status).to be_kind_of(::Gitlab::Kubernetes::RolloutStatus)
expect(rollout_status.deployments.map(&:labels)).to eq([{ 'app' => 'env-000000' }])
end
end
end
describe '#calculate_reactive_cache' do
before { stub_kubeclient_pods }
subject { service.calculate_reactive_cache }
context 'when service is inactive' do
......@@ -211,20 +214,31 @@ describe KubernetesService, models: true, caching: true do
it { is_expected.to be_nil }
end
context 'when kubernetes responds with valid pods' do
it { is_expected.to eq(pods: [kube_pod]) }
context 'when kubernetes responds with valid pods and deployments' do
before do
stub_kubeclient_pods
stub_kubeclient_deployments
end
it { is_expected.to eq(pods: [kube_pod], deployments: [kube_deployment]) }
end
context 'when kubernetes responds with 500' do
let(:pods_response) { { status: 500 } }
context 'when kubernetes responds with 500s' do
before do
stub_kubeclient_pods(status: 500)
stub_kubeclient_deployments(status: 500)
end
it { expect { subject }.to raise_error(KubeException) }
end
context 'when kubernetes responds with 404' do
let(:pods_response) { { status: 404 } }
context 'when kubernetes responds with 404s' do
before do
stub_kubeclient_pods(status: 404)
stub_kubeclient_deployments(status: 404)
end
it { is_expected.to eq(pods: []) }
it { is_expected.to eq(pods: [], deployments: []) }
end
end
end
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe EnvironmentEntity do
let(:entity) do
described_class.new(environment, request: double)
described_class.new(environment, request: double(user: nil))
end
let(:environment) { create(:environment) }
......@@ -15,4 +15,16 @@ describe EnvironmentEntity do
it 'exposes core elements of environment' do
expect(subject).to include(:id, :name, :state, :environment_path)
end
context 'with deployment service ready' do
before do
allow(environment).to receive(:deployment_service_ready?).and_return(true)
end
it 'exposes rollout_status_path' do
expected = '/' + [environment.project.full_path, 'environments', environment.id, 'status.json'].join('/')
expect(subject[:rollout_status_path]).to eq(expected)
end
end
end
require 'spec_helper'
describe RolloutStatusEntity do
include KubernetesHelpers
let(:entity) do
described_class.new(rollout_status, request: double)
end
let(:rollout_status) { ::Gitlab::Kubernetes::RolloutStatus.from_specs(kube_deployment) }
subject { entity.as_json }
it { is_expected.to have_key(:instances) }
it { is_expected.to have_key(:completion) }
it { is_expected.to have_key(:is_completed) }
end
module KubernetesHelpers
include Gitlab::Kubernetes
def kube_discovery_body
def kube_response(body)
{ body: body.to_json }
end
def kube_pods_response
kube_response(kube_pods_body)
end
def kube_deployments_response
kube_response(kube_deployments_body)
end
def stub_kubeclient_discover
WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body))
WebMock.stub_request(:get, service.api_url + '/apis/extensions/v1beta1').to_return(kube_response(kube_v1beta1_discovery_body))
end
def stub_kubeclient_pods(response = nil)
stub_kubeclient_discover
pods_url = service.api_url + "/api/v1/namespaces/#{service.namespace}/pods"
WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response)
end
def stub_kubeclient_deployments(response = nil)
stub_kubeclient_discover
deployments_url = service.api_url + "/apis/extensions/v1beta1/namespaces/#{service.namespace}/deployments"
WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response)
end
def kube_v1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
{ "name" => "pods", "namespaced" => true, "kind" => "Pod" },
]
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
],
}
end
def kube_pods_body(*pods)
{ "kind" => "PodList",
"items" => [kube_pod] }
def kube_v1beta1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
{ "name" => "pods", "namespaced" => true, "kind" => "Pod" },
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
],
}
end
def kube_pods_body
{
"kind" => "PodList",
"items" => [kube_pod]
}
end
def kube_deployments_body
{
"kind" => "DeploymentList",
"items" => [kube_deployment]
}
end
# This is a partial response, it will have many more elements in reality but
# these are the ones we care about at the moment
def kube_pod(app: "valid-pod-label")
def kube_pod(name: "kube-pod", app: "valid-pod-label")
{
"metadata" => {
"name" => "kube-pod",
"name" => name,
"creationTimestamp" => "2016-11-25T19:55:19Z",
"labels" => { "app" => app },
},
......@@ -34,6 +85,23 @@ module KubernetesHelpers
}
end
def kube_deployment(name: "kube-deployment", app: "valid-deployment-label")
{
"metadata" => {
"name" => name,
"generation" => 4,
"labels" => { "app" => app },
},
"spec" => { "replicas" => 3 },
"status" => {
"observedGeneration" => 4,
"replicas" => 3,
"updatedReplicas" => 3,
"availableReplicas" => 3,
},
}
end
def kube_terminals(service, pod)
pod_name = pod['metadata']['name']
containers = pod['spec']['containers']
......
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