lib/seira/pods.rb in seira-0.3.7 vs lib/seira/pods.rb in seira-0.4.0

- old
+ new

@@ -61,113 +61,92 @@ def run_top kubectl("top pod #{pod_name} --containers", context: context) end def run_connect - # If a pod name is specified, connect to that pod; otherwise pick a random web pod - target_pod_name = pod_name || Helpers.fetch_pods(app: app, filters: { tier: 'web' }).sample&.dig('metadata', 'name') + tier = nil + pod_name = nil + dedicated = false + command = 'sh' - if target_pod_name - connect_to_pod(target_pod_name) - else - puts "Could not find web pod to connect to" - end - end - - def run_run - # Set defaults - tier = 'web' - clear_commands = false - detached = false - container_name = app - - # Loop through args and process any that aren't just the command to run - loop do - arg = args.first - if arg.nil? - puts 'Please specify a command to run' - exit(1) - end - break unless arg.start_with? '--' + args.each do |arg| if arg.start_with? '--tier=' tier = arg.split('=')[1] - elsif arg == '--clear-commands' - clear_commands = true - elsif arg == '--detached' - detached = true - elsif arg.start_with? '--container=' - container_name = 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 - args.shift end - # Any remaining args are the command to run - command = args.join(' ') - - # Find a 'template' pod from the proper tier - template_pod = Helpers.fetch_pods(app: app, filters: { tier: tier }).first - if template_pod.nil? - puts "Unable to find #{tier} tier pod to copy config from" + # If a pod name is specified, connect to that pod + # If a tier is specified, connect to a random pod from that tier + # Otherwise connect to a terminal pod + target_pod = pod_name || Helpers.fetch_pods(context: context, filters: { tier: tier || 'terminal' }).sample + if target_pod.nil? + puts 'Could not find pod to connect to' exit(1) end - # Use that template pod's configuration to create a new temporary pod - temp_name = "#{app}-temp-#{Random.unique_name}" - spec = template_pod['spec'] - temp_pod = { - apiVersion: template_pod['apiVersion'], - kind: 'Pod', - spec: spec, - metadata: { - name: temp_name + if dedicated + # 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. + temp_name = "temp-#{Random.unique_name}" + + # Construct a spec for the temp pod + spec = target_pod['spec'] + temp_pod = { + apiVersion: target_pod['apiVersion'], + kind: 'Pod', + spec: spec, + metadata: { + name: temp_name + } } - } - spec['restartPolicy'] = 'Never' - if clear_commands + # 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'] = ['bash', '-c', 'tail -f /dev/null'] + container['command'] = ['sleep', '86400'] # 86400 seconds = 24 hours end - end - if detached - target_container = spec['containers'].find { |container| container['name'] == container_name } - if target_container.nil? - puts "Could not find container '#{container_name}' to run command in" + 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 - target_container['command'] = ['bash', '-c', command] - end - puts "Creating temporary pod #{temp_name}" - unless system("kubectl --namespace=#{app} create -f - <<JSON\n#{temp_pod.to_json}\nJSON") - puts 'Failed to create pod' - exit(1) - end - - unless detached - # Check pod status until it's ready to connect to - print 'Waiting for pod to start...' + print 'Waiting for dedicated pod to start...' loop do - pod = JSON.parse(`kubectl --namespace=#{app} get pods/#{temp_name} -o json`) + pod = JSON.parse(kubectl("get pods/#{temp_name} -o json", context: context, return_output: true)) break if pod['status']['phase'] == 'Running' print '.' sleep 1 end print "\n" - # Connect to the pod, running the specified command connect_to_pod(temp_name, command) - # Clean up - unless system("kubectl --namespace=#{app} delete pod #{temp_name}") - puts "Warning: failed to clean up pod #{temp_name}" + # Clean up on disconnect so temp pod isn't taking up resources + unless kubectl("delete pods/#{temp_name}", context: context) + puts 'Failed to delete temp pod' end + 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')) end end - def connect_to_pod(name, command = 'bash') + def connect_to_pod(name, command = 'sh') puts "Connecting to #{name}..." system("kubectl exec -ti #{name} --namespace=#{app} -- #{command}") end end end