cl-magic 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+
7
+ require 'cl/magic/common/common_options.rb'
8
+ require 'cl/magic/common/logging.rb'
9
+ require 'cl/magic/common/gcloud.rb'
10
+ require 'cl/magic/common/kubectl.rb'
11
+
12
+ @logger = get_logger()
13
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
14
+
15
+ #
16
+ # Features
17
+ #
18
+
19
+ def do_work(options)
20
+ if TTY::Prompt.new.yes?("Are you sure you want to restart #{options[:deployment]}?")
21
+ cmd = "kubectl rollout restart deployment/#{options[:deployment]} --namespace=#{options[:namespace]}"
22
+ @logger.puts
23
+ @logger.wait cmd
24
+ exec(cmd)
25
+ end
26
+ end
27
+
28
+ #
29
+ # Options
30
+ #
31
+
32
+ options = {}
33
+ global_banner = <<DOC
34
+
35
+ Restart a deployment for a service to refresh all the containers
36
+
37
+ Usage: #{@cl_cmd_name} [options]
38
+
39
+ DOC
40
+
41
+ global = OptionParser.new do |g|
42
+ g.banner = global_banner
43
+ add_help_and_verbose(g)
44
+
45
+ g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
46
+ options[:kube_context] = v
47
+ end
48
+
49
+ g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
50
+ options[:namespace] = v
51
+ end
52
+
53
+ g.on("-d", "--deployment DEPLOYMENT", "a kubectl deployment") do |v|
54
+ options[:deployment] = v
55
+ end
56
+
57
+ g.on("-x", "use magic tools context") do |v|
58
+ options[:ktx] = v
59
+ end
60
+
61
+ end
62
+
63
+ #
64
+ # Run
65
+ #
66
+
67
+ global.parse(ARGV)
68
+
69
+ # set: context and namespace
70
+ set_context_and_namespace(options)
71
+ set_ktx(options)
72
+
73
+ # set: deployment
74
+ options[:deployment] = pick_kubectl_deployment(options).first
75
+
76
+ # display full command
77
+ @logger.puts ""
78
+ write_history("""#{@cl_cmd_name} \\
79
+ --context=#{options[:kube_context]}
80
+ --namespace=#{options[:namespace]}
81
+ --deployment=#{options[:deployment]}
82
+ """)
83
+
84
+ do_work(options)
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+
6
+ require 'cl/magic/common/common_options.rb'
7
+ require 'cl/magic/common/logging.rb'
8
+ require 'cl/magic/common/kubectl.rb'
9
+
10
+ @logger = get_logger()
11
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
12
+
13
+ #
14
+ # Features
15
+ #
16
+
17
+ def do_search(options)
18
+
19
+ # k8 api-resources
20
+ unless options[:kube_service_name]
21
+ @logger.puts ""
22
+ cmd = "kubectl api-resources --verbs=list --namespaced -o name | grep -v events.events.k8s.io | grep -v events | sort | uniq"
23
+ @logger.wait cmd
24
+ api_resources = TTY::Command.new(:printer => :null).run(cmd).collect { |line| line.split() }
25
+ options[:kube_service_name] = pick_single_result(api_resources, "Pick a resource").first
26
+ end
27
+
28
+ # display full command
29
+ write_history("""#{@cl_cmd_name} \\
30
+ --context=#{options[:kube_context]} \\
31
+ --service=#{options[:kube_service_name]} \\
32
+ --namespace=#{options[:namespace]}
33
+ """)
34
+
35
+ # get resources
36
+ @logger.puts ""
37
+ namespace = options[:namespace] ? "-n #{options[:namespace]}" : "--all-namespaces"
38
+ cmd = "kubectl get #{namespace} --ignore-not-found #{options[:kube_service_name]}"
39
+ cmd += " | grep #{options[:pattern]}" if options[:pattern]
40
+ @logger.wait cmd
41
+ result = TTY::Command.new(:printer => :null).run(cmd).out
42
+ only_one_result = options[:pattern] ? result.lines.count == 1 : result.lines.count == 2
43
+
44
+ # print resources
45
+ unless only_one_result
46
+ puts result
47
+ @logger.puts
48
+ end
49
+
50
+ # describe resource
51
+ if only_one_result or TTY::Prompt.new.yes?("Describe one of these resources?")
52
+ num_headers = options[:pattern] ? 0 : 1
53
+ resources_by_type = parse_table_results(cmd, "No resources found", num_headers=num_headers)
54
+ selection_index = 1
55
+ resource = pick_single_result(resources_by_type, "show resource?", nil, nil, selection_index)
56
+ cmd = "kubectl describe #{options[:kube_service_name]} #{resource[0]} --namespace=#{options[:namespace]}"
57
+ @logger.puts
58
+ @logger.wait cmd
59
+ puts TTY::Command.new(:printer => :null).run(cmd)
60
+ end
61
+ end
62
+
63
+ #
64
+ # Options
65
+ #
66
+
67
+ options = {}
68
+ global_banner = <<DOC
69
+
70
+ Search for k8 resources
71
+
72
+ Usage: #{@cl_cmd_name} [options]
73
+
74
+ DOC
75
+
76
+ global = OptionParser.new do |g|
77
+ g.banner = global_banner
78
+ add_help_and_verbose(g)
79
+
80
+ g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
81
+ options[:kube_context] = v
82
+ end
83
+
84
+ g.on("-s", "--service SERVICE_NAME", "a kubectl api-service name") do |v|
85
+ options[:kube_service_name] = v
86
+ end
87
+
88
+ g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
89
+ options[:namespace] = v
90
+ end
91
+
92
+ g.on("-p", "--pattern PATTERN", "pattern to grep for") do |v|
93
+ options[:pattern] = v
94
+ end
95
+
96
+ g.on("-x", "use magic tools context") do |v|
97
+ options[:ktx] = v
98
+ end
99
+ end
100
+
101
+ #
102
+ # Run
103
+ #
104
+
105
+ global.parse(ARGV)
106
+
107
+ # set: context
108
+ set_context_and_namespace(options) if options[:ktx]
109
+ options[:kube_context] = pick_kubectl_context(options[:kube_context])
110
+
111
+ do_search(options)
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+ require 'json'
7
+ require 'pastel'
8
+
9
+ require 'cl/magic/common/common_options.rb'
10
+ require 'cl/magic/common/logging.rb'
11
+ require 'cl/magic/common/kubectl.rb'
12
+
13
+ @logger = get_logger()
14
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
15
+
16
+ #
17
+ # Features
18
+ #
19
+
20
+ def do_search(options)
21
+
22
+ # k8 api-resources
23
+ unless options[:kube_service_name]
24
+ @logger.puts ""
25
+ cmd = "kubectl api-resources --verbs=list --namespaced -o name | grep -v events.events.k8s.io | grep -v events | sort | uniq"
26
+ @logger.wait cmd
27
+ api_resources = TTY::Command.new(:printer => :null).run(cmd).collect { |line| line.split() }
28
+ options[:kube_service_name] = pick_single_result(api_resources, "Pick a resource").first
29
+ end
30
+
31
+ get_kubectl_contexts().each do |context|
32
+
33
+ context_name = context[1]
34
+
35
+ # set context
36
+ cmd = "kubectl config use-context #{context_name}"
37
+ TTY::Command.new(:printer => :null).run(cmd)
38
+
39
+ # searching in
40
+ puts "searching: #{context_name}"
41
+
42
+ # grep services
43
+ cmd = "kubectl get --all-namespaces --ignore-not-found #{options[:kube_service_name]}"
44
+ cmd += " | grep #{options[:pattern]}" if options[:pattern]
45
+
46
+ results = TTY::Command.new(:printer => :null).run!(cmd) do |out, err|
47
+ unless out.nil?
48
+ puts out
49
+ @logger.puts ""
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ #
57
+ # Options
58
+ #
59
+
60
+ options = {}
61
+ global_banner = <<DOC
62
+
63
+ Grep across all clusters and namespaces
64
+
65
+ Usage: #{@cl_cmd_name} [filter-name] [options]
66
+
67
+ DOC
68
+
69
+ global = OptionParser.new do |g|
70
+ g.banner = global_banner
71
+
72
+ g.on("-s", "--service SERVICE_NAME", "a kubectl api-service name; defaults to 'services'") do |v|
73
+ options[:kube_service_name] = v
74
+ end
75
+
76
+ g.on("-p", "--pattern PATTERN", "pattern to grep for") do |v|
77
+ options[:pattern] = v
78
+ end
79
+
80
+ g.on("-x", "use magic tools context") do |v|
81
+ options[:ktx] = v
82
+ end
83
+ end
84
+
85
+ #
86
+ # Run
87
+ #
88
+
89
+ global.parse(ARGV)
90
+
91
+ # display full command
92
+ write_history("""#{@cl_cmd_name} \\
93
+ --grep=#{options[:pattern]} \\
94
+ --service=#{options[:kube_service_name]}
95
+ """)
96
+
97
+ do_search(options)
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+ require 'json'
7
+ require 'pastel'
8
+
9
+ require 'cl/magic/common/common_options.rb'
10
+ require 'cl/magic/common/logging.rb'
11
+ require 'cl/magic/common/kubectl.rb'
12
+
13
+ @logger = get_logger()
14
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
15
+
16
+ #
17
+ # Features
18
+ #
19
+
20
+ def visit_pod(options)
21
+ shell_command = options[:bash] ? "bash" : "sh"
22
+ cmd = "kubectl exec -it #{options[:pod_name]} --container #{options[:container_name]} --namespace #{options[:namespace]} -- #{shell_command}"
23
+ @logger.puts
24
+ @logger.wait cmd
25
+ exec(cmd)
26
+ end
27
+
28
+ #
29
+ # Options
30
+ #
31
+
32
+ options = {}
33
+ global_banner = <<DOC
34
+
35
+ Ssh into a container
36
+
37
+ Usage: #{@cl_cmd_name} [options]
38
+
39
+ DOC
40
+
41
+ global = OptionParser.new do |g|
42
+ g.banner = global_banner
43
+
44
+ g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
45
+ options[:kube_context] = v
46
+ end
47
+
48
+ g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
49
+ options[:namespace] = v
50
+ end
51
+
52
+ g.on("-d", "--deployment NAME", "a kubernetes deployment name") do |v|
53
+ options[:deployment_name] = v
54
+ end
55
+
56
+ g.on("-p", "--pod POD_NAME", "a kubernetes pod name") do |v|
57
+ options[:pod_name] = v
58
+ end
59
+
60
+ g.on("--container CONTAINER_NAME", "a kubernetes container you'd like to visit") do |v|
61
+ options[:container_name] = v
62
+ end
63
+
64
+ g.on("-x", "use magic tools context") do |v|
65
+ options[:ktx] = v
66
+ end
67
+
68
+ g.on("-b", "--bash", "bash instead of shell") do |v|
69
+ options[:bash] = v
70
+ end
71
+ end
72
+
73
+ #
74
+ # Run
75
+ #
76
+
77
+ global.parse(ARGV)
78
+
79
+ # set everything
80
+ set_context_namespace_deployment_pod_container_options(options)
81
+ set_ktx(options)
82
+
83
+ # display full command
84
+ write_history("""#{@cl_cmd_name} \\
85
+ --context=#{options[:kube_context]} \\
86
+ --namespace=#{options[:namespace]} \\
87
+ --deployment=#{options[:deployment_name]} \\
88
+ --pod=#{options[:pod_name]} \\
89
+ --container=#{options[:container_name]} \\
90
+ #{options[:bash] ? "--bash" : ""}
91
+ """)
92
+
93
+ # visit pod
94
+ visit_pod(options)
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+
7
+ require 'cl/magic/common/common_options.rb'
8
+ require 'cl/magic/common/logging.rb'
9
+ require 'cl/magic/common/gcloud.rb'
10
+ require 'cl/magic/common/kubectl.rb'
11
+
12
+ @logger = get_logger()
13
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
14
+
15
+ #
16
+ # Features
17
+ #
18
+
19
+ def do_work(options)
20
+ while true
21
+ tty_command = TTY::Command.new(printer: :null)
22
+ out, err = tty_command.run(ARGV.join(' '))
23
+ puts out
24
+ puts
25
+ sleep(1)
26
+ end
27
+ end
28
+
29
+ #
30
+ # Options
31
+ #
32
+
33
+ options = {}
34
+ global_banner = <<DOC
35
+
36
+ A sandbox to try things
37
+
38
+ Usage: #{@cl_cmd_name} [options]
39
+
40
+ DOC
41
+
42
+ global = OptionParser.new do |g|
43
+ g.banner = global_banner
44
+ add_help_and_verbose(g)
45
+ end
46
+
47
+ #
48
+ # Run
49
+ #
50
+
51
+ do_work(options)
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+
7
+ require 'cl/magic/common/common_options.rb'
8
+ require 'cl/magic/common/logging.rb'
9
+ require 'cl/magic/common/gcloud.rb'
10
+ require 'cl/magic/common/kubectl.rb'
11
+
12
+ @logger = get_logger()
13
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
14
+
15
+ #
16
+ # Features
17
+ #
18
+
19
+ def do_work(options)
20
+ write_history("""#{@cl_cmd_name}""")
21
+ @logger.success "Hello World"
22
+ end
23
+
24
+ #
25
+ # Options
26
+ #
27
+
28
+ options = {}
29
+ global_banner = <<DOC
30
+
31
+ A sandbox to try things
32
+
33
+ Usage: #{@cl_cmd_name} [options]
34
+
35
+ DOC
36
+
37
+ global = OptionParser.new do |g|
38
+ g.banner = global_banner
39
+ add_help_and_verbose(g)
40
+ end
41
+
42
+ #
43
+ # Run
44
+ #
45
+
46
+ @working_dir = ENV['CL_WORKING_DIR'] # passed through cl-magic to here
47
+ global.parse(ARGV)
48
+
49
+ do_work(options)
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'optparse/subcommand'
4
+ require 'tty-command'
5
+ require 'tty-prompt'
6
+
7
+ require 'cl/magic/common/common_options.rb'
8
+ require 'cl/magic/common/logging.rb'
9
+ require 'cl/magic/common/gcloud.rb'
10
+ require 'cl/magic/common/kubectl.rb'
11
+
12
+ @logger = get_logger()
13
+ @cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
14
+
15
+ #
16
+ # Features
17
+ #
18
+
19
+ def transverse_vault_path(path)
20
+
21
+ # list the folder
22
+ cmd = "vault list #{path}"
23
+ results = parse_table_results(cmd, "no secrets", num_headers=2)
24
+ selected_path = pick_single_result(results, "").first
25
+ new_path = File.join(path, selected_path)
26
+
27
+ if new_path.end_with? '/'
28
+ transverse_vault_path(new_path) # another folder, recurse
29
+ else
30
+ return new_path # picked a file
31
+ end
32
+ end
33
+
34
+ def print_secret(secret_path)
35
+
36
+ write_history("""#{@cl_cmd_name} \\
37
+ --secret=#{secret_path}
38
+ """)
39
+
40
+ cmd = "vault read #{secret_path}"
41
+ puts TTY::Command.new(:printer => :null).run(cmd).out
42
+ end
43
+
44
+ #
45
+ # Options
46
+ #
47
+
48
+ options = {}
49
+ global_banner = <<DOC
50
+
51
+ Browse secrets path and print a secret
52
+
53
+ Usage: #{@cl_cmd_name} [options]
54
+
55
+ DOC
56
+
57
+ global = OptionParser.new do |g|
58
+ g.banner = global_banner
59
+ add_help_and_verbose(g)
60
+
61
+ g.on("-p", "--path PATH", "a vault path to start from") do |v|
62
+ options[:vault_path] = v
63
+ end
64
+
65
+ g.on("-s", "--secret SECRET_PATH", "an exact secret to get") do |v|
66
+ options[:exact_secret_path] = v
67
+ end
68
+ end
69
+
70
+ #
71
+ # Run
72
+ #
73
+
74
+ global.parse(ARGV)
75
+
76
+ if options[:vault_path].nil?
77
+ options[:vault_path] = "secret"
78
+ end
79
+
80
+ if options[:exact_secret_path].nil?
81
+ options[:exact_secret_path] = transverse_vault_path(options[:vault_path])
82
+ end
83
+
84
+ print_secret(options[:exact_secret_path])
@@ -0,0 +1,16 @@
1
+
2
+ def add_help_and_verbose(opts)
3
+ add_verbose(opts)
4
+ add_help(opts)
5
+ end
6
+
7
+ def add_verbose(opts)
8
+ opts.on("-v", "--[no-]verbose")
9
+ end
10
+
11
+ def add_help(opts)
12
+ opts.on("-h", "--help") do
13
+ puts opts
14
+ exit
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ require 'json'
2
+ require 'tty-command'
3
+ require 'tty-prompt'
4
+ require 'cl/magic/common/logging.rb'
5
+ require 'cl/magic/common/parse_and_pick.rb'
6
+
7
+ #
8
+ # gcloud GET
9
+ #
10
+
11
+ def get_gcloud_projects(filter=nil)
12
+ filter_option = "--filter #{filter}" if filter
13
+ command = "gcloud projects list #{filter_option}"
14
+ error_message = "No gcloud projects? Are you authenticated?"
15
+ return parse_table_results(command, error_message)
16
+ end
17
+
18
+ def get_current_gcloud_project()
19
+ command = "gcloud config get-value project"
20
+ return TTY::Command.new(:printer => :null).run(command).out.strip.chomp
21
+ end
22
+
23
+ def get_sql_instances()
24
+ command = "gcloud sql instances list"
25
+ return parse_table_results(command, 'No sql instances. :(')
26
+ end
27
+
28
+ def get_sql_users(instance)
29
+ command = "gcloud sql users list --instance=#{instance.first}"
30
+ return parse_table_results(command, 'No sql users. :(')
31
+ end
32
+
33
+ def get_sql_databases(instance)
34
+ command = "gcloud sql databases list --instance=#{instance.first}"
35
+ return parse_table_results(command, 'No sql databases. :(')
36
+ end
37
+
38
+ #
39
+ # Misc
40
+ #
41
+
42
+ def pick_gcloud_project(filter=nil)
43
+
44
+ prev_project = get_current_gcloud_project()
45
+
46
+ # pick content
47
+ projects = get_gcloud_projects(filter)
48
+ selected_project = pick_single_result(projects, 'Pick a project', nil, prev_project)
49
+
50
+ # change context
51
+ if selected_project.first != prev_project
52
+ command = "gcloud config set project #{selected_project.first}"
53
+ @logger.wait command
54
+ TTY::Command.new(:printer => :null).run(command)
55
+ else
56
+ @logger.info "project already set to #{selected_project.first}"
57
+ end
58
+
59
+ return selected_project
60
+ end
61
+
62
+ def check_gcloud_project(project)
63
+ command = "gcloud info"
64
+ result = TTY::Command.new(:printer => :null).run(command)
65
+
66
+ current_project = result.select {|line| line.include? 'Project'}.first.split(': ').last
67
+ if current_project != "[#{current_project}]"
68
+ @logger.warn "Incorrect gcloud project: #{current_project}"
69
+ @logger.warn "Use `gcloud config set project #{project}` and try again."
70
+ end
71
+ end