Add helm CLI wrapper

This commit is contained in:
Alessio Caiazza 2017-10-16 17:51:58 +02:00
parent 4a9cf1dc00
commit 6d462cea77
No known key found for this signature in database
GPG Key ID: 8655B9CB5B8B512E
2 changed files with 127 additions and 0 deletions

57
lib/gitlab/helm.rb Normal file
View File

@ -0,0 +1,57 @@
module Gitlab
class Helm
Error = Class.new(StandardError)
attr_accessor :namespace
attr_accessor :logger
delegate :debug, :debug?, to: :logger, allow_nil: true
def initialize(namespace, kubeconfig, logger: nil)
self.namespace = namespace
self.logger = logger
@kubeconfig = kubeconfig
end
def init!
prepare_env do |env|
helm('init', '--upgrade', env: env)
end
end
def install_or_upgrade!(app_name, chart)
prepare_env do |env|
helm('init', '--client-only', env: env)
helm('upgrade', '--install', '--namespace', namespace, app_name, chart, env: env)
end
end
private
def prepare_env(*args, &blk)
Dir.mktmpdir(['helm', namespace]) do |tmpdir|
kubeconfig_path = File.join(tmpdir, 'kubeconfig')
env = {
'HELM_HOME' => File.join(tmpdir, 'helm'),
'TILLER_NAMESPACE' => namespace,
'KUBECONFIG' => kubeconfig_path
}
File.open(kubeconfig_path, 'w') { |c| c << YAML.dump(@kubeconfig) }
debug("HELM: Running in tmpdir #{tmpdir}")
yield(env) if block_given?
end
end
def helm(*args, env: {})
Open3.popen3(env, 'helm', *args) do |_, stdout, stderr, wait_thr|
exit_status = wait_thr.value
stdout.readlines.each { |l| debug("HELM: #{l.chomp}") } if debug?
raise Error, stderr.read.chomp unless exit_status.success?
end
end
end
end

View File

@ -0,0 +1,70 @@
# coding: utf-8
require 'spec_helper'
describe Gitlab::Helm do
let(:namespace) { 'rails-spec' }
let(:kubeconfig) {}
let(:logger) {}
subject { described_class.new(namespace, kubeconfig, logger: logger)}
def mock_helm_invocation(success:, error: '')
stderr = StringIO.new(error)
process_status = double('process_status')
wait_thr = double('wait_thread')
expect(Open3).to receive(:popen3).at_least(:once).and_yield(StringIO.new, StringIO.new, stderr, wait_thr)
expect(wait_thr).to receive(:value).at_least(:once).and_return(process_status)
expect(process_status).to receive(:success?).at_least(:once).and_return(success)
end
shared_examples 'invokes helm binary' do |method, args|
context 'when helm binary fails' do
let(:error_text) { 'Something went wrong' }
before do
mock_helm_invocation(success: false, error: error_text)
end
it 'throws exception' do
expect { subject.send(method, *args) }.to raise_exception(Gitlab::Helm::Error, error_text)
end
end
context 'when helm binary exit-code is 0' do
before do
mock_helm_invocation(success: true)
end
it "doesn't raise exceptions" do
expect { subject.send(method, *args) }.not_to raise_exception
end
end
end
it { is_expected.to delegate_method(:debug).to(:logger) }
it { is_expected.to delegate_method(:debug?).to(:logger) }
describe '#init!' do
it 'invokes helm init --upgrade' do
expect(subject).to receive(:helm).with('init', '--upgrade', env: instance_of(Hash))
subject.init!
end
it_should_behave_like 'invokes helm binary', :init!, []
end
describe '#install_or_upgrade!' do
let(:app_name) { 'app_name' }
let(:chart) { 'stable/a_chart' }
it 'invokes helm upgrade --install --namespace namespace app_name chart' do
expect(subject).to receive(:helm).with('init', '--client-only', env: instance_of(Hash)).ordered.once
expect(subject).to receive(:helm).with('upgrade', '--install', '--namespace', namespace, app_name, chart, env: instance_of(Hash)).ordered.once
subject.install_or_upgrade!(app_name, chart)
end
it_should_behave_like 'invokes helm binary', :install_or_upgrade!, %w[app_name chart]
end
end