Skip to content

Commit 6b63096

Browse files
authored
Merge pull request reclaim-the-stack#14 from barsoom/support-namespaces
Support creating and editing secrets in multiple namespaces
2 parents 62e9b7b + 8cf6bc5 commit 6b63096

File tree

1 file changed

+81
-43
lines changed

1 file changed

+81
-43
lines changed

k

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,12 @@ def print_commands
178178
puts "k rollback <application>" + gray(" show prompt to rollback an application")
179179
puts "k run <application> <command>" + gray(" run a command using a one off pod")
180180
puts "k scale <application> <deployment>:<replicas>" + gray(" scale a deployment in an application")
181-
puts "k secrets [<specific-secret>]" + gray(" lists secrets including usage details")
182-
puts "k secrets:create <secret-name>" + gray(" create a new secret")
183-
puts "k secrets:edit <secret-name>" + gray(" edit a secret")
184-
puts "k secrets:get <secret-name> <key>" + gray(" get a single secret value")
185-
puts "k secrets:set <secret-name> <key>=<value> [<key2>=<value2> ...]" + gray(" set new secret values")
186-
puts "k secrets:unset <secret-name> <key> [<key2> ...]" + gray(" unset / delete secret values")
181+
puts "k secrets [namespace:][<specific-secret>]" + gray(" lists secrets including usage details")
182+
puts "k secrets:create [namespace:]<secret-name>" + gray(" create a new secret")
183+
puts "k secrets:edit [namespace:]<secret-name>" + gray(" edit a secret")
184+
puts "k secrets:get [namespace:]<secret-name> <key>" + gray(" get a single secret value")
185+
puts "k secrets:set [namespace:]<secret-name> <key>=<value> [<key2>=<value2> ...]" + gray(" set new secret values")
186+
puts "k secrets:unset [namespace:]<secret-name> <key> [<key2> ...]" + gray(" unset / delete secret values")
187187
puts "k update" + gray(" update k to the latest version")
188188
puts ""
189189
puts "DEBUGGING COMMANDS:"
@@ -1671,7 +1671,11 @@ def scale
16711671
end
16721672

16731673
def secrets
1674-
specific_secret = ARGV.delete_at(0)
1674+
namespace, specific_secret = ARGV.delete_at(0)&.split(":")
1675+
unless specific_secret
1676+
specific_secret = namespace
1677+
namespace = "default"
1678+
end
16751679

16761680
in_argo_repo do
16771681
application_secrets = Dir.glob("applications/*/values.yaml").each_with_object({}) do |path, hash|
@@ -1700,6 +1704,7 @@ def secrets
17001704
next unless YAML.load_file(secret_path).fetch("spec").fetch("template")["type"] == "opaque"
17011705

17021706
secret = File.basename(secret_path, ".yaml")
1707+
secret = secret.sub(/__/, ":")
17031708
puts bold(secret)
17041709
application_secrets[secret]&.each do |application|
17051710
puts gray(" #{application}")
@@ -1708,23 +1713,30 @@ def secrets
17081713
end
17091714
end
17101715

1711-
puts "Use k secrets:edit #{specific_secret || '<secret-name>'} to edit"
1716+
optional_namespace = namespace == "default" ? "" : "#{namespace}:"
1717+
optional_namespace = "[namespace:]" unless specific_secret
1718+
puts "Use k secrets:edit #{optional_namespace}#{specific_secret || '<secret-name>'} to edit"
17121719
end
17131720
end
17141721

17151722
def secrets_edit
1716-
shared_secret = ARGV.delete_at(0)
1717-
abort "Must pass name of secret, eg. k secrets:edit <shared-secret-name>" unless shared_secret
1723+
namespace, shared_secret = ARGV.delete_at(0)&.split(":")
1724+
unless shared_secret
1725+
shared_secret = namespace
1726+
namespace = "default"
1727+
end
1728+
1729+
abort "Must pass name of secret, eg. k secrets:edit [namespace:]<shared-secret-name>" unless shared_secret
17181730
abort "Missing $EDITOR environment variable, eg: export EDITOR='code --wait --new-window'" unless ENV.key?("EDITOR")
17191731

17201732
in_argo_repo do
17211733
require "base64"
17221734

1723-
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} -o yaml")
1735+
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} --namespace #{namespace} -o yaml")
17241736
original_env = original_secret.fetch("data").transform_values(&Base64.method(:strict_decode64))
17251737

17261738
# Write temporary file and launch editor
1727-
tmp_file = "/#{Dir.tmpdir}/#{shared_secret}.yaml"
1739+
tmp_file = "/#{Dir.tmpdir}/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
17281740
File.write tmp_file, original_env.to_yaml.delete_prefix("---\n")
17291741
system "#{ENV.fetch('EDITOR')} #{tmp_file}"
17301742

@@ -1740,7 +1752,7 @@ def secrets_edit
17401752
original_secret["data"] = data
17411753

17421754
File.write(tmp_file, original_secret.to_yaml)
1743-
kubeseal tmp_file, "applications/shared-secrets/#{shared_secret}.yaml"
1755+
kubeseal tmp_file, "applications/shared-secrets/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
17441756
File.delete tmp_file
17451757

17461758
changed_variables = new_env.keys.select do |name|
@@ -1749,7 +1761,7 @@ def secrets_edit
17491761
added_variables = new_env.keys - original_env.keys
17501762
deleted_variables = original_env.keys - new_env.keys
17511763

1752-
commit_message = "shared-secrets: edited #{shared_secret}\n\n"
1764+
commit_message = "shared-secrets: edited #{shared_secret} in namespace #{namespace}\n\n"
17531765
commit_message << "Changed: #{changed_variables.join(' ')}\n" unless changed_variables.empty?
17541766
commit_message << "Added: #{added_variables.join(' ')}\n" unless added_variables.empty?
17551767
commit_message << "Deleted: #{deleted_variables.join(' ')}\n" unless deleted_variables.empty?
@@ -1762,19 +1774,24 @@ def secrets_edit
17621774
end
17631775

17641776
def secrets_get
1765-
if ARGV.length != 2
1766-
puts "Usage: k secrets:get <secret-name> <key>"
1767-
exit
1777+
namespace, shared_secret = ARGV.delete_at(0)&.split(":")
1778+
key = ARGV.delete_at(0)
1779+
unless shared_secret
1780+
shared_secret = namespace
1781+
namespace = "default"
17681782
end
17691783

1770-
shared_secret = ARGV.delete_at(0)
1771-
key = ARGV.delete_at(0)
1784+
unless shared_secret && key
1785+
puts "Usage: k secrets:get [namespace:]<secret-name> <key>"
1786+
exit
1787+
end
17721788

17731789
in_argo_repo do
1774-
secret_path = "applications/shared-secrets/#{shared_secret}.yaml"
1790+
secret_path = "applications/shared-secrets/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
17751791
abort "No shared secret found at '#{secret_path}'" unless File.exist?(secret_path)
17761792

1777-
kubernetes_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} -o yaml")
1793+
namespace_option = namespace == "default" ? "" : "--namespace #{namespace}"
1794+
kubernetes_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} -o yaml #{namespace_option}")
17781795
secret = kubernetes_secret["data"]
17791796

17801797
abort "Error: key '#{key}' not found in secret '#{shared_secret}'" unless secret
@@ -1788,11 +1805,15 @@ end
17881805

17891806
def secrets_set
17901807
if ARGV.length < 2
1791-
puts "Usage: k secrets:set <secret-name> <key>=<value> [<key2>=<value2> ...]"
1808+
puts "Usage: k secrets:set [namespace:]<secret-name> <key>=<value> [<key2>=<value2> ...]"
17921809
exit
17931810
end
17941811

1795-
shared_secret = ARGV.delete_at(0)
1812+
namespace, shared_secret = ARGV.delete_at(0)&.split(":")
1813+
unless shared_secret
1814+
shared_secret = namespace
1815+
namespace = "default"
1816+
end
17961817
new_env = ARGV.map { |argument| argument.split("=", 2) }
17971818

17981819
abort "Error: all environment variables must be in the form <key>=<value>" if new_env.any? { _1.length != 2 }
@@ -1803,12 +1824,12 @@ def secrets_set
18031824
abort "Error: invalid environment variable names: #{bad_keys.join(', ')}" unless bad_keys.empty?
18041825

18051826
in_argo_repo do
1806-
secret_path = "applications/shared-secrets/#{shared_secret}.yaml"
1827+
secret_path = "applications/shared-secrets/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
18071828
abort "No shared secret found at '#{secret_path}'" unless File.exist?(secret_path)
18081829

18091830
require "base64"
18101831

1811-
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} -o yaml")
1832+
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} --namespace #{namespace} -o yaml")
18121833
original_env = original_secret.fetch("data").transform_values(&Base64.method(:strict_decode64))
18131834

18141835
new_env = original_env.merge(new_env)
@@ -1831,7 +1852,7 @@ def secrets_set
18311852
end
18321853
added_variables = new_env.keys - original_env.keys
18331854

1834-
commit_message = "shared-secrets: edited #{shared_secret}\n\n"
1855+
commit_message = "shared-secrets: edited #{shared_secret} in namespace #{namespace}\n\n"
18351856
commit_message << "Changed: #{changed_variables.join(' ')}\n" unless changed_variables.empty?
18361857
commit_message << "Added: #{added_variables.join(' ')}\n" unless added_variables.empty?
18371858

@@ -1843,23 +1864,29 @@ def secrets_set
18431864
end
18441865

18451866
def secrets_unset
1846-
if ARGV.length < 2
1847-
puts "Usage: k secrets:unset <secret-name> <key1> [<key2> ...]"
1848-
exit
1867+
namespace, shared_secret = ARGV.delete_at(0)&.split(":")
1868+
unless shared_secret
1869+
shared_secret = namespace
1870+
namespace = "default"
18491871
end
18501872

1851-
shared_secret = ARGV.delete_at(0)
1873+
keys = ARGV
1874+
1875+
unless shared_secret && keys
1876+
puts "Usage: k secrets:unset [namespace:]<secret-name> <key> [<key2> ...]"
1877+
exit
1878+
end
18521879

18531880
in_argo_repo do
1854-
secret_path = "applications/shared-secrets/#{shared_secret}.yaml"
1881+
secret_path = "applications/shared-secrets/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
18551882
abort "No shared secret found at '#{secret_path}'" unless File.exist?(secret_path)
18561883

18571884
require "base64"
18581885

1859-
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} -o yaml")
1886+
original_secret = YAML.safe_load read_kubectl("get secret #{shared_secret} --namespace #{namespace} -o yaml")
18601887
original_env = original_secret.fetch("data").transform_values(&Base64.method(:strict_decode64))
18611888

1862-
new_env = original_env.except(*ARGV)
1889+
new_env = original_env.except(*keys)
18631890

18641891
if new_env == original_env
18651892
puts "No changes detected, skipping..."
@@ -1869,14 +1896,14 @@ def secrets_unset
18691896
data = new_env.transform_values(&:to_s).transform_values(&Base64.method(:strict_encode64))
18701897
original_secret["data"] = data
18711898

1872-
tmp_file = "/#{Dir.tmpdir}/#{shared_secret}.yaml"
1899+
tmp_file = "/#{Dir.tmpdir}/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
18731900
File.write(tmp_file, original_secret.to_yaml)
18741901
kubeseal tmp_file, secret_path
18751902
File.delete tmp_file
18761903

18771904
deleted_variables = original_env.keys - new_env.keys
18781905

1879-
commit_message = "shared-secrets: edited #{shared_secret}\n\n"
1906+
commit_message = "shared-secrets: edited #{shared_secret} in namespace #{namespace}\n\n"
18801907
commit_message << "Deleted: #{deleted_variables.join(' ')}\n"
18811908

18821909
puts commit_message
@@ -1887,19 +1914,26 @@ def secrets_unset
18871914
end
18881915

18891916
def secrets_create
1890-
secret = ARGV.delete_at(0)
1891-
abort "Must pass name of the new secret, eg. k secrets:create <secret-name>" unless secret
1917+
namespace, shared_secret = ARGV.delete_at(0)&.split(":")
1918+
unless shared_secret
1919+
shared_secret = namespace
1920+
namespace = "default"
1921+
end
1922+
1923+
abort "Must pass name of the new secret, eg. k secrets:create [namespace:]<secret-name>" unless shared_secret
18921924
abort "Missing $EDITOR environment variable, eg: export EDITOR='code --wait --new-window'" unless ENV.key?("EDITOR")
18931925

18941926
require "base64"
18951927

18961928
in_argo_repo do
1897-
secret_path = "applications/shared-secrets/#{secret}.yaml"
1929+
secret_path = "applications/shared-secrets/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
1930+
18981931
if File.exist?(secret_path)
1899-
abort "Error: A secret named '#{secret}' already exists, run 'k secrets:edit #{secret}' to edit it"
1932+
error_namespace_prefix = namespace == "default" ? "" : "#{namespace}:"
1933+
abort "Error: A secret named '#{shared_secret}' in namespace #{namespace} already exists, run 'k secrets:edit #{error_namespace_prefix}#{shared_secret}' to edit it"
19001934
end
19011935

1902-
tmp_file = "/#{Dir.tmpdir}/#{secret}.yaml"
1936+
tmp_file = "/#{Dir.tmpdir}/#{namespace_prefix(namespace)}#{shared_secret}.yaml"
19031937
File.write(
19041938
tmp_file,
19051939
<<~YAML,
@@ -1918,7 +1952,7 @@ def secrets_create
19181952
secret_yaml = {
19191953
"apiVersion" => "v1",
19201954
"kind" => "Secret",
1921-
"metadata" => { "name" => secret },
1955+
"metadata" => { "name" => shared_secret, "namespace" => namespace },
19221956
"type" => "opaque",
19231957
"data" => data,
19241958
}.to_yaml
@@ -1928,10 +1962,10 @@ def secrets_create
19281962
File.delete tmp_file
19291963

19301964
system_or_die "git add #{secret_path}"
1931-
system_or_die %(git commit -m "shared-secrets: add #{secret}" --quiet)
1965+
system_or_die %(git commit -m "shared-secrets: add #{shared_secret} in namespace #{namespace}" --quiet)
19321966
safe_git_push
19331967

1934-
puts "Successfully created the secret '#{secret}'"
1968+
puts "Successfully created the secret '#{shared_secret}' in namespace #{namespace}"
19351969
end
19361970
end
19371971

@@ -2749,6 +2783,10 @@ end
27492783

27502784
PRIVATE_METHODS_AFTER_COMMANDS = private_methods - PRIVATE_METHODS_BEFORE_COMMANDS
27512785

2786+
def namespace_prefix(namespace)
2787+
namespace == "default" ? "" : "#{namespace}__"
2788+
end
2789+
27522790
def verify_inside_context_repository!
27532791
context_repo = URI K_CONTEXT.fetch("repository").delete_suffix(".git").delete_suffix("/")
27542792
current_repo = URI `git remote get-url origin`.strip.delete_suffix(".git").delete_suffix("/")

0 commit comments

Comments
 (0)