Skip to content

Instantly share code, notes, and snippets.

@steigr
Last active October 25, 2021 10:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steigr/7f11eae8bea303e26f617d38f24ccd8c to your computer and use it in GitHub Desktop.
Save steigr/7f11eae8bea303e26f617d38f24ccd8c to your computer and use it in GitHub Desktop.
Running commands inside pods
#!/usr/bin/env ruby
# install kubeclient and websocket-client-simple gems
#
# this is an example extending Kubeclient::Client with an get_pod_exec method
#
# it's just a POC
# I did run a pod with `kubectl -n kube-system run --tty --stdin --image=debian:buster-slim kubeclient`
# installed base ruby and required gems like:
# `apt-get update && apt-get install -y ruby ruby-dev build-essential && gem install --no-ri --no-rdoc kubeclient websocket-client-simple`
#
# As exec uses some weird Websocket-Protocol ( Channel + Data, see lines 94/96/121) I use an extra
# websocket-client with the same authorization headers and building
# the query string to send commands in. If the command is a string or array with just one element
# is should run within /bin/sh. If there is no tty, the same.
#
#
# References:
# https://github.com/abonas/kubeclient#inside-a-kubernetes-cluster
# https://github.com/abonas/kubeclient/blob/master/lib/kubeclient/common.rb#L363
# https://blog.openshift.com/executing-commands-in-pods-using-k8s-api/
# https://github.com/shokai/websocket-client-simple
require "kubeclient"
require "websocket-client-simple"
module kubeclientClientCreatePodExecMod
EXEC_STDIN = 0
EXEC_STDOUT = 1
EXEC_STDERR = 2
def get_pod_exec(pod_name, namespace,
container: nil, command: ["/bin/sh"],
stdin: true, stdout: true,
stderr: true, tty: true)
params = {}
params[:stdin] = true if stdin
params[:stdout] = true if stdout
params[:stderr] = true if stderr
params[:tty] = true if tty
params[:container] = container unless container.nil?
if command.is_a? String
params[:command] = ["/bin/sh","-c",command]
elsif command.size == 1
params[:command] = ["/bin/sh","-c",command.first]
elsif tty==false
params[:command] = ["/bin/sh","-c",command.map{|word| "\"#{word}\"" }.join(" ")]
else
params[:command] ||= command
end
ns = build_namespace_prefix(namespace)
url = URI.parse(rest_client[ns + "pods/#{pod_name}/exec"].url)
commands = params.delete(:command).map{|x| "command=#{x}" }
url.query = (params.map{|k,v| "#{k}=#{v}" } + commands ).join("&")
ws = WebSocket::Client::Simple.connect(url.to_s,headers: @headers)
if block_given?
handle_exception do
yield ws
end
else
return ws
end
end
end
Kubeclient::Client.include(kubeclientClientCreatePodExecMod)
auth_options = {
bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token'
}
ssl_options = {}
if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
end
client = Kubeclient::Client.new(
'https://kubernetes.default.svc',
'v1',
auth_options: auth_options,
ssl_options: ssl_options
)
client.discover
pod = client.get_pods.select{|p| p.metadata.labels["run"] == "kubeclient" }.first
cmd = <<-EOC
set -x
echo "hallo welt"
exit
EOC
cmd = ""
ARGF.each do |line|
cmd += line + "\n"
end
chan = client.get_pod_exec(pod.metadata.name,pod.metadata.namespace,command:[URI.encode(cmd)])
chan.on(:message) do |msg|
if msg.type == :close
chan.close
exit(0)
end
unless msg.data.empty?
data = msg.data.unpack("C*")
case data.shift
when Kubeclient::Client::EXEC_STDOUT
STDOUT.puts "O " + data.pack("C*").force_encoding('utf-8')
when Kubeclient::Client::EXEC_STDERR
STDERR.puts "E " + data.pack("C*").force_encoding('utf-8')
else
STDERR.puts "W Unknown channel"
STDERR.puts "W " + data.inspect
end
end
end
chan.on(:error) do |msg|
chan.close
exit(1)
end
chan.on(:close) do |msg|
chan.close
exit(0)
end
loop do
chan.send(0)
sleep(30)
end
# Delete all file in /tmp
# chan.send(("rm /tmp/*").pack("C*").unshift(Kubeclient::Client::EXEC_STDIN))
@cben
Copy link

cben commented Feb 20, 2020

Link back to discussion: ManageIQ/kubeclient#353

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment