From 9ee41ad021dc62f5db6903c9c700b8f59f21136a Mon Sep 17 00:00:00 2001 From: Max Roth Date: Thu, 19 Feb 2026 15:21:45 +0100 Subject: [PATCH] k run: allow node to be specified with --node In some cases we want the be able to run a script or console on a specific node, like network bandwidth for instance. --- k | 60 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/k b/k index 292333a..a5ae176 100755 --- a/k +++ b/k @@ -1162,24 +1162,41 @@ def pg_unused_indexes SQL end +# Parse named options from ARGV, modifying it in place. Remaining positional args stay in ARGV. +# +# flags: boolean switches that can appear anywhere (eg. --disable-timeout) +# params: options that take a value and must appear before positional args +# accepts --key=value or --key value syntax +# +# Returns a Hash keyed by the option name without leading dashes, eg. { "tag" => "v1", "disable-timeout" => true } +def parse_options!(flags: [], params: []) + options = {} + + flags.each { |flag| options[flag.delete_prefix("--")] = !!ARGV.delete(flag) } + + params.each do |param| + key = param.delete_prefix("--") + if ARGV[0]&.start_with?("#{param}=") + options[key] = ARGV.delete_at(0).split("=", 2).last + abort "ERROR: Must provide a value with #{param}=" if options[key].empty? + elsif ARGV[0] == param + ARGV.delete_at(0) + options[key] = ARGV.delete_at(0) + abort "ERROR: Must provide a value with #{param}" if options[key].nil? || options[key].empty? + elsif ARGV.any? { |arg| arg == param || arg.start_with?("#{param}=") } + puts yellow('Warning: ') + gray("#{param} argument will be part of the running command, if you intended to use it you must pass it before the command") + end + end + + options +end + def run application = ARGV.delete_at(0) - disable_timeout = ARGV.delete("--disable-timeout") + options = parse_options!(flags: %w[--disable-timeout], params: %w[--tag --node]) - # Handle --tag= argument, can be passed as --tag= or --tag and must be before the command - if ARGV[0]&.start_with?("--tag=") - tag = ARGV.delete_at(0).split("=", 2).last - abort "ERROR: Must provide a tag value with --tag=" if tag.empty? - elsif ARGV[0] == "--tag" - ARGV.delete_at(0) - tag = ARGV.delete_at(0) - abort "ERROR: Must provide a tag value with --tag" if tag.nil? || tag.empty? - elsif ARGV.any? { |arg| arg == "--tag" || arg.start_with?("--tag=") } - puts yellow('Warning: ') + gray("--tag argument will be part of the running command, if you intended to set the image tag you must pass it before the command") - end - - abort "Must pass name of application, eg. k run [--tag=] [--disable-timeout] " unless application - abort "Must pass command to run, eg. k run [--tag=] [--disable-timeout]" if ARGV.empty? + abort "Must pass name of application, eg. k run [--tag=] [--node=] [--disable-timeout] " unless application + abort "Must pass command to run, eg. k run [--tag=] [--node=] [--disable-timeout]" if ARGV.empty? resources = resources_for_argocd_application("deployments", application) if resources.empty? @@ -1212,11 +1229,13 @@ def run image = run_container.fetch("image") # replace image tag if --tag was provided - if tag - image = "#{image.split(':').first}:#{tag}" + if options["tag"] + image = "#{image.split(':').first}:#{options['tag']}" puts gray("applying --tag argument to image: #{image}") end + + pod_template = { apiVersion: "v1", kind: "Pod", @@ -1233,12 +1252,17 @@ def run envFrom: run_container["envFrom"] || [], env: run_container["env"] || [], imagePullPolicy: "IfNotPresent", - command: ["sleep", disable_timeout ? "86400" : "3600"], # shutdown the pod after 1 hour or 24 hours + command: ["sleep", options["disable-timeout"] ? "86400" : "3600"], # shutdown the pod after 1 hour or 24 hours }, ], }, } + if options["node"] + puts gray("applying nodeName: #{options["node"]} to pod template spec") + pod_template[:spec][:nodeName] = options["node"] + end + puts "Creating pod #{pod_name}..." system("echo '#{pod_template.to_json}' | kubectl --context #{KUBECTL_CONTEXT} apply -f -") || abort("failed to create pod")