class Seira::Pods

Constants

SUMMARY
VALID_ACTIONS

Attributes

action[R]
app[R]
args[R]
context[R]
pod_name[R]

Public Class Methods

new(app:, action:, args:, context:) click to toggle source
# File lib/seira/pods.rb, line 12
def initialize(app:, action:, args:, context:)
  @app = app
  @action = action
  @context = context
  @args = args
  @pod_name = args[0]
end

Public Instance Methods

run() click to toggle source
# File lib/seira/pods.rb, line 20
def run
  case action
  when 'help'
    run_help
  when 'list'
    run_list
  when 'delete'
    run_delete
  when 'logs'
    run_logs
  when 'top'
    run_top
  when 'connect'
    run_connect
  when 'run'
    run_run
  else
    fail "Unknown command encountered"
  end
end

Private Instance Methods

clean_up_pod(pod_name) click to toggle source

Clean up pod so it isn't taking up resources. Usually only for dedicated pods

# File lib/seira/pods.rb, line 173
def clean_up_pod(pod_name)
  unless kubectl("delete pods/#{pod_name}", context: context)
    puts 'Failed to delete temp pod'
  end
end
connect_to_pod(name, command = 'sh') click to toggle source
# File lib/seira/pods.rb, line 179
def connect_to_pod(name, command = 'sh')
  puts "Connecting to #{name}..."
  system("kubectl exec -ti #{name} --namespace=#{app} -- #{command}")
end
create_dedicated_pod(target_pod, pod_name = "temp- click to toggle source

Create a dedicated temp pod to run in This is useful if you would like to have a persistent connection that doesn't get killed when someone updates the terminal deployment, or if you want to avoid noisy neighbors connected to the same pod.

# File lib/seira/pods.rb, line 124
def create_dedicated_pod(target_pod, pod_name = "temp-#{Random.unique_name}")
  spec = target_pod['spec']

  # Clear out some fields that are maintained by Kubernetes
  # and we don't want to duplicate from the old pod.
  # If we don't clear nodeName, it'll try and schedule the
  # new duplicated pod on the same node which may not fit.
  spec['nodeName'] = nil

  temp_pod = {
    apiVersion: target_pod['apiVersion'],
    kind: 'Pod',
    spec: spec,
    metadata: {
      name: pod_name,
      annotations: {
        owner: Helpers.shell_username
      }
    }
  }
  # Don't restart the pod when it dies
  spec['restartPolicy'] = 'Never'
  # Overwrite container commands with something that times out, so if the client disconnects
  # there's a limited amount of time that the temp pod is still taking up resources
  # Note that this will break a pods which depends on containers running real commands, but
  # for a simple terminal pod it's fine
  spec['containers'].each do |container|
    container['command'] = %w[sleep 86400] # 86400 seconds = 24 hours
  end

  puts 'Creating dedicated pod...'
  unless system("kubectl --namespace=#{app} create -f - <<JSON\n#{temp_pod.to_json}\nJSON")
    puts 'Failed to create dedicated pod'
    exit(1)
  end

  print 'Waiting for dedicated pod to start...'
  loop do
    pod = JSON.parse(kubectl("get pods/#{pod_name} -o json", context: context, return_output: true))
    break if pod['status']['phase'] == 'Running'
    print '.'
    sleep 1
  end
  print "\n"

  pod_name
end
run_connect() click to toggle source
# File lib/seira/pods.rb, line 65
def run_connect
  tier = nil
  pod_name = nil
  dedicated = false
  command = 'sh'

  args.each do |arg|
    if arg.start_with? '--tier='
      tier = arg.split('=')[1]
    elsif arg.start_with? '--pod='
      pod_name = arg.split('=')[1]
    elsif arg.start_with? '--command='
      command = arg.split('=')[1..-1].join('=')
    elsif arg == '--dedicated'
      dedicated = true
    else
      puts "Warning: Unrecognized argument #{arg}"
    end
  end

  # If a pod name is specified, find the pod with that name
  existing_pod = Helpers.fetch_pod(pod_name, context: context) unless pod_name.to_s.empty?

  # Use existing pod if found and not --dedicated
  # Otherwise, connect to a random pod from the specified tier or the 'terminal' tier if unspecified
  target_pod = if existing_pod && dedicated
                 puts "Cannot create new dedicated pod with name: #{pod_name}"
                 puts "A pod with this name already exists"
                 exit(1)
               elsif existing_pod
                 existing_pod
               elsif dedicated || pod_name.to_s.empty?
                 Helpers.fetch_pods(context: context, filters: { tier: tier || 'terminal' }).sample
               end

  if target_pod.nil?
    puts 'Could not find pod to connect to'
    exit(1)
  end

  if dedicated
    new_pod = if pod_name.nil?
                create_dedicated_pod(target_pod)
              else
                create_dedicated_pod(target_pod, pod_name)
              end

    connect_to_pod(new_pod, command)
    clean_up_pod(new_pod)
  else
    # If we don't need a dedicated pod, it's way easier - just connect to the already running one
    connect_to_pod(target_pod.dig('metadata', 'name'), command)
  end
end
run_delete() click to toggle source
# File lib/seira/pods.rb, line 53
def run_delete
  kubectl("delete pod #{pod_name}", context: context)
end
run_help() click to toggle source
# File lib/seira/pods.rb, line 43
def run_help
  puts SUMMARY
  puts "\n\n"
  puts "TODO"
end
run_list() click to toggle source
# File lib/seira/pods.rb, line 49
def run_list
  kubectl("get pods -o wide", context: context)
end
run_logs() click to toggle source
# File lib/seira/pods.rb, line 57
def run_logs
  kubectl("logs #{pod_name} -c #{app}")
end
run_top() click to toggle source
# File lib/seira/pods.rb, line 61
def run_top
  kubectl("top pod #{pod_name} --containers", context: context)
end