class Kitchen::Driver::K8s
@author Chris McFee <cmcfee@kent.edu>
Public Instance Methods
create(state)
click to toggle source
(see Base#create)
# File lib/kitchen/driver/k8s.rb, line 109 def create(state) return if state[:pod_id] pod_id = config[:pod_name].downcase state[:pod_id] = pod_id state[:namespace] = config[:namespace] client = kubectl_client # Render pod pod = render_pod_info(pod_id) debug("Creating pod with YAML:\n#{pod}\n") client.create_pod(render_pod_info(pod_id)) # Wait until pod is running status = nil start_time = Time.now while status != 'Running' if Time.now - start_time > 20 info("Waiting for pod #{pod_id} to be running, currently #{status}") end sleep(1) status = client.get_pod(pod_id, config[:namespace]).status.phase end platform_dependencies.each do |cmd| run_command(kubectl_command('exec', '--tty', '--container=default', pod_id, '--', *Shellwords.split(wrap_command(cmd)))) end if config[:provision_command] config[:provision_command].each do |cmd| run_command(kubectl_command('exec', '--tty', '--container=default', pod_id, '--', *Shellwords.split(wrap_command(cmd)))) end end state[:pod_id] = pod_id end
default_platform()
click to toggle source
# File lib/kitchen/driver/k8s.rb, line 51 def default_platform instance.platform.name.split('-').first end
destroy(state)
click to toggle source
(see Base#destroy)
# File lib/kitchen/driver/k8s.rb, line 141 def destroy(state) return unless state[:pod_id] client = kubectl_client client.delete_pod(state[:pod_id], config[:namespace]) end
finalize_config!(instance)
click to toggle source
@api private
Calls superclass method
# File lib/kitchen/driver/k8s.rb, line 56 def finalize_config!(instance) super.tap do # Force the use of the Kubernetes transport since it isn't much use # without that. instance.transport = Kitchen::Transport::K8s.new(config) # Leave room for the possibility of other provisioners in the future, # but force some options we need. if instance.provisioner.is_a?(Kitchen::Provisioner::ChefBase) instance.provisioner.send(:config).update( require_chef_omnibus: false, product_name: nil, chef_omnibus_root: '/opt/chef', sudo: false ) end # Ditto to the above, other verifiers will need their own hacks, but # this is a start at least. if instance.verifier.is_a?(Kitchen::Verifier::Busser) instance.verifier.send(:config).update( root_path: '/tmp/kitchen/verifier', sudo: false, ) elsif defined?(Kitchen::Verifier::Inspec) && instance.verifier.is_a?(Kitchen::Verifier::Inspec) # Monkeypatch kitchen-inspec to use a copy of the k8s train transport. require 'kitchen/verifier/k8s' _config = config # Because closure madness. old_runner_options = instance.verifier.method(:runner_options) instance.verifier.send(:define_singleton_method, :runner_options) do |transport, state = {}, platform = nil, suite = nil| if transport.is_a?(Kitchen::Transport::K8s) { backend: 'k8s_hack', logger: logger, pod: state[:pod_id], container: 'default', kubectl_path: _config[:binary], context: _config[:context], }.tap do |runner_options| # Copied directly from kitchen-inspec because there is no way not to. Sigh. runner_options['color'] = (config[:color].nil? ? true : config[:color]) runner_options['format'] = config[:format] unless config[:format].nil? runner_options['output'] = config[:output] % { platform: platform, suite: suite } unless config[:output].nil? runner_options['profiles_path'] = config[:profiles_path] unless config[:profiles_path].nil? runner_options[:controls] = config[:controls] end else old_runner_options.call(transport, state, platform, suite) end end end end end
Protected Instance Methods
kubectl_client()
click to toggle source
Get an instance of Kubeclient::Client
# File lib/kitchen/driver/k8s.rb, line 154 def kubectl_client kubeconfig = Kubeclient::Config.read(config[:kubeconfig]) client = Kubeclient::Client.new( kubeconfig.context.api_endpoint, kubeconfig.context.api_version, { ssl_options: kubeconfig.context.ssl_options, auth_options: kubeconfig.context.auth_options } ) return client end
platform_dependencies()
click to toggle source
Build platform dependent commands
# File lib/kitchen/driver/k8s.rb, line 168 def platform_dependencies case config[:platform] when 'debian', 'ubuntu' packages = [ 'export DEBIAN_FRONTEND=noninteractive', 'apt-get update', 'apt-get install -y sudo curl lsb-release' ] when 'rhel', 'centos', 'fedora' packages = [ 'yum install -y sudo which curl', 'yum clean all' ] when 'opensuse', 'sles' packages = [ 'zypper install -y sudo which curl' ] when 'arch' packages = [ 'pacman --noconfirm -Sy archlinux-keyring', 'pacman-db-upgrade', 'pacman --noconfirm -Sy sudo curl' ] when 'gentoo' packages = [ 'emerge --sync', 'emerge app-admin/sudo' ] when 'gentoo-paludis' packages = [ 'cave sync', 'cave resolve -zx app-admin/sudo' ] else raise ActionFailed, "Unknown platform '#{config[:platform]}'" end return packages end
render_pod_info(pod_id)
click to toggle source
Create JSON pod information
# File lib/kitchen/driver/k8s.rb, line 208 def render_pod_info(pod_id) pod = Kubeclient::Resource.new pod.metadata = {} pod.metadata.name = pod_id pod.metadata.namespace = config[:namespace] pod.metadata.labels = { heritage: 'kitchen-k8s' } pod.metadata.annotations = { 'kitchen.ci/kitchen-instance' => instance.name, 'kitchen.ci/kitchen-platform' => instance.platform.name, 'kitchen.ci/kitchen-created-by' => Etc.getlogin || 'unknown', 'kitchen.ci/kitchen-created-on' => Socket.gethostname } pod.spec = {} pod.spec.containers = [{ name: 'default', image: config[:image], command: ['/bin/sh', '-c', "trap 'exit 0' TERM; sleep 2147483647 & wait"], securityContext: { privileged: true } }] pod.spec.containers[0].env = config[:environment] if config[:environment] pod.spec.serviceAccount = config[:service_account] pod.spec.serviceAccountName = config[:service_account] return pod end
wrap_command(cmd)
click to toggle source
# File lib/kitchen/driver/k8s.rb, line 149 def wrap_command(cmd) cmd.match(/\Ash\s\-c/) ? cmd : Util.wrap_command(cmd.gsub('\'', "'\\\\''")) end