cl-magic 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +47 -0
- data/README.md +211 -0
- data/bin/cl +17 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/cl-magic.gemspec +38 -0
- data/lib/cl/magic/cl +97 -0
- data/lib/cl/magic/cl-auth +109 -0
- data/lib/cl/magic/cl-aws-okta-auth +52 -0
- data/lib/cl/magic/cl-aws-okta-env +79 -0
- data/lib/cl/magic/cl-dk +402 -0
- data/lib/cl/magic/cl-envkey +70 -0
- data/lib/cl/magic/cl-gc-sql +135 -0
- data/lib/cl/magic/cl-gc-tags +171 -0
- data/lib/cl/magic/cl-glab-commit +68 -0
- data/lib/cl/magic/cl-history +44 -0
- data/lib/cl/magic/cl-kube-cp +99 -0
- data/lib/cl/magic/cl-kube-deployment +120 -0
- data/lib/cl/magic/cl-kube-ktx +60 -0
- data/lib/cl/magic/cl-kube-logs +114 -0
- data/lib/cl/magic/cl-kube-restart +84 -0
- data/lib/cl/magic/cl-kube-search +111 -0
- data/lib/cl/magic/cl-kube-search-all +97 -0
- data/lib/cl/magic/cl-kube-ssh +94 -0
- data/lib/cl/magic/cl-poll +51 -0
- data/lib/cl/magic/cl-sandbox +49 -0
- data/lib/cl/magic/cl-vault +84 -0
- data/lib/cl/magic/common/common_options.rb +16 -0
- data/lib/cl/magic/common/gcloud.rb +71 -0
- data/lib/cl/magic/common/kubectl.rb +236 -0
- data/lib/cl/magic/common/logging.rb +25 -0
- data/lib/cl/magic/common/parse_and_pick.rb +81 -0
- data/lib/cl/magic/version.rb +7 -0
- data/lib/cl/magic.rb +9 -0
- metadata +180 -0
@@ -0,0 +1,171 @@
|
|
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/gcloud.rb'
|
9
|
+
require 'cl/magic/common/kubectl.rb'
|
10
|
+
|
11
|
+
@logger = get_logger()
|
12
|
+
@cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
|
13
|
+
|
14
|
+
#
|
15
|
+
# Features
|
16
|
+
#
|
17
|
+
|
18
|
+
def get_full_image_name(options)
|
19
|
+
if options[:image].include?('/')
|
20
|
+
return options[:image]
|
21
|
+
else
|
22
|
+
return "gcr.io/#{options[:project]}/#{options[:image]}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_gcloud_cmd(options)
|
27
|
+
if options[:image].nil?
|
28
|
+
@logger.error("Please provide `-i IMAGE`")
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
full_image_name = get_full_image_name(options)
|
32
|
+
return "gcloud container images list-tags #{full_image_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_newest_image_digest(options)
|
36
|
+
@logger.info "fetching newest digest"
|
37
|
+
cmd = get_gcloud_cmd(options)
|
38
|
+
cmd += " | sed -n 2p | tr -s ' ' | cut -d ' ' -f 2"
|
39
|
+
@logger.wait cmd
|
40
|
+
out, err = TTY::Command.new(:printer => :null).run("#{cmd}")
|
41
|
+
newest_digest = out.chomp
|
42
|
+
if newest_digest.include? "latest"
|
43
|
+
@logger.info("#{newest_digest} is already the latest")
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
return newest_digest
|
47
|
+
end
|
48
|
+
|
49
|
+
def tag_image(options, image_digest, tag)
|
50
|
+
full_image_name = get_full_image_name(options)
|
51
|
+
@logger.info "tagging", [options[:image], image_digest, tag]
|
52
|
+
cmd = "gcloud container images add-tag --quiet #{full_image_name}:#{image_digest} #{full_image_name}:#{tag}"
|
53
|
+
@logger.wait cmd
|
54
|
+
out, err = TTY::Command.new(:printer => :null).run(cmd)
|
55
|
+
puts out
|
56
|
+
end
|
57
|
+
|
58
|
+
def tag_latest(options)
|
59
|
+
if options[:tag].nil?
|
60
|
+
tag = 'latest'
|
61
|
+
else
|
62
|
+
tag = options[:tag]
|
63
|
+
end
|
64
|
+
|
65
|
+
if options[:image_digest]
|
66
|
+
image_digest = options[:image_digest]
|
67
|
+
else
|
68
|
+
image_digest = get_newest_image_digest(options)
|
69
|
+
@logger.success "Got newest: #{image_digest}"
|
70
|
+
end
|
71
|
+
|
72
|
+
tag_image(options, image_digest, tag)
|
73
|
+
end
|
74
|
+
|
75
|
+
def list_tags(options)
|
76
|
+
cmd = get_gcloud_cmd(options)
|
77
|
+
|
78
|
+
# display full command
|
79
|
+
write_history("""
|
80
|
+
#{@cl_cmd_name} list \\
|
81
|
+
--image=#{options[:image]}
|
82
|
+
--project=#{options[:project]}
|
83
|
+
""")
|
84
|
+
@logger.wait cmd
|
85
|
+
out, err = TTY::Command.new(:printer => :null).run(cmd)
|
86
|
+
puts out
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Options
|
91
|
+
#
|
92
|
+
|
93
|
+
options = {}
|
94
|
+
global_banner = <<DOC
|
95
|
+
|
96
|
+
Work with google cloud tags.
|
97
|
+
|
98
|
+
These are important for local docker development as the latest production image
|
99
|
+
will often be what we pull down to run our compose stacks. Let's make it easier
|
100
|
+
for devs to list and tag images locally.
|
101
|
+
|
102
|
+
Usage: #{@cl_cmd_name} [options]
|
103
|
+
|
104
|
+
DOC
|
105
|
+
|
106
|
+
list_banner = <<DOC
|
107
|
+
|
108
|
+
List all the tags for a google cloud image
|
109
|
+
|
110
|
+
Usage: #{@cl_cmd_name} list [options]
|
111
|
+
|
112
|
+
DOC
|
113
|
+
|
114
|
+
tag_banner = <<DOC
|
115
|
+
|
116
|
+
Tag a google cloud image
|
117
|
+
|
118
|
+
Usage: #{@cl_cmd_name} tag [options]
|
119
|
+
|
120
|
+
DOC
|
121
|
+
|
122
|
+
def add_image_option(parser, options)
|
123
|
+
parser.on("-i", "--image IMAGE", "docker images in google cloud") do |v|
|
124
|
+
options[:image] = v
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
global = OptionParser.new do |g|
|
129
|
+
g.banner = global_banner
|
130
|
+
add_help_and_verbose(g)
|
131
|
+
|
132
|
+
g.subcommand 'list' do |s|
|
133
|
+
s.banner = list_banner
|
134
|
+
options[:action] = :list
|
135
|
+
add_image_option(s, options)
|
136
|
+
|
137
|
+
s.on("-p", "--project NAME", "google cloud project name") do |v|
|
138
|
+
options[:gc_project] = v
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
g.subcommand 'tag' do |s|
|
143
|
+
s.banner = tag_banner
|
144
|
+
options[:action] = :tag
|
145
|
+
add_image_option(s, options)
|
146
|
+
|
147
|
+
s.on("-t", "--tag TAG", "tag name to put on the image in google cloud") do |v|
|
148
|
+
options[:tag] = v
|
149
|
+
end
|
150
|
+
s.on("-d", "--image-digest DIGEST", "image digest to tag") do |v|
|
151
|
+
options[:image_digest] = v
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Run
|
159
|
+
#
|
160
|
+
|
161
|
+
global.parse(ARGV)
|
162
|
+
|
163
|
+
case options[:action]
|
164
|
+
when :list
|
165
|
+
options[:project] = pick_gcloud_project(options[:project]).first
|
166
|
+
list_tags(options)
|
167
|
+
when :tag
|
168
|
+
tag_latest(options)
|
169
|
+
else
|
170
|
+
puts global.parse! %w[--help]
|
171
|
+
end
|
@@ -0,0 +1,68 @@
|
|
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
|
+
cmd = "glab api /projects/:id/repository/commits/#{options[:commit]} | jq .web_url | xargs open"
|
21
|
+
@logger.info cmd
|
22
|
+
exec("cd #{@working_dir} && #{cmd}")
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Options
|
27
|
+
#
|
28
|
+
|
29
|
+
options = {}
|
30
|
+
global_banner = <<DOC
|
31
|
+
|
32
|
+
A sandbox to try things
|
33
|
+
|
34
|
+
Usage: #{@cl_cmd_name} [options]
|
35
|
+
|
36
|
+
DOC
|
37
|
+
|
38
|
+
global = OptionParser.new do |g|
|
39
|
+
g.banner = global_banner
|
40
|
+
add_help_and_verbose(g)
|
41
|
+
|
42
|
+
g.on("-c", "--commit sha", "the commit you want to view in the browser") do |v|
|
43
|
+
options[:commit] = v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Run
|
49
|
+
#
|
50
|
+
|
51
|
+
@working_dir = ENV['CL_WORKING_DIR'] # passed through cl-magic to here
|
52
|
+
global.parse(ARGV)
|
53
|
+
|
54
|
+
unless options[:commit]
|
55
|
+
command = "cd #{@working_dir} && git log --oneline | head -c 100000"
|
56
|
+
results = TTY::Command.new(:printer => :null).run(command).collect{|c|
|
57
|
+
parts = c.split(' ')
|
58
|
+
[parts.first, parts[1..].join(' ')]
|
59
|
+
}
|
60
|
+
options[:commit] = pick_single_result(results, "").first
|
61
|
+
puts options[:commit]
|
62
|
+
end
|
63
|
+
|
64
|
+
write_history("""#{@cl_cmd_name} \\
|
65
|
+
--commit=#{options[:commit]} \\
|
66
|
+
""")
|
67
|
+
|
68
|
+
do_work(options)
|
@@ -0,0 +1,44 @@
|
|
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
|
+
|
9
|
+
@logger = get_logger()
|
10
|
+
@cl_cmd_name = File.basename(__FILE__).split('-').join(' ')
|
11
|
+
|
12
|
+
#
|
13
|
+
# Features
|
14
|
+
#
|
15
|
+
|
16
|
+
def tail_history(options)
|
17
|
+
exec("tail -n 100 #{Dir.home}/.cl_history")
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Options
|
22
|
+
#
|
23
|
+
|
24
|
+
options = {}
|
25
|
+
global_banner = <<DOC
|
26
|
+
|
27
|
+
History of commands you have run
|
28
|
+
|
29
|
+
Usage: #{@cl_cmd_name} [options]
|
30
|
+
|
31
|
+
DOC
|
32
|
+
|
33
|
+
global = OptionParser.new do |g|
|
34
|
+
g.banner = global_banner
|
35
|
+
add_help_and_verbose(g)
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Run
|
40
|
+
#
|
41
|
+
|
42
|
+
global.parse(ARGV)
|
43
|
+
|
44
|
+
tail_history(options)
|
@@ -0,0 +1,99 @@
|
|
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 upload_file(options)
|
20
|
+
cmd = "cd #{@working_dir} && kubectl -n #{options[:namespace]} -c #{options[:container_name]} cp #{options[:local_filepath]} #{options[:pod_name]}:#{options[:remote_path]}"
|
21
|
+
@logger.puts
|
22
|
+
@logger.wait cmd
|
23
|
+
exec(cmd)
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Options
|
28
|
+
#
|
29
|
+
|
30
|
+
options = {}
|
31
|
+
global_banner = <<DOC
|
32
|
+
|
33
|
+
Copy a file to the container
|
34
|
+
|
35
|
+
Usage: #{@cl_cmd_name} [options]
|
36
|
+
|
37
|
+
DOC
|
38
|
+
|
39
|
+
global = OptionParser.new do |g|
|
40
|
+
g.banner = global_banner
|
41
|
+
add_help_and_verbose(g)
|
42
|
+
|
43
|
+
g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
|
44
|
+
options[:kube_context] = v
|
45
|
+
end
|
46
|
+
|
47
|
+
g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
|
48
|
+
options[:namespace] = v
|
49
|
+
end
|
50
|
+
|
51
|
+
g.on("-d", "--deployment NAME", "a kubernetes deployment name") do |v|
|
52
|
+
options[:deployment_name] = v
|
53
|
+
end
|
54
|
+
|
55
|
+
g.on("-p", "--pod POD_NAME", "a kubernetes pod name") do |v|
|
56
|
+
options[:pod_name] = v
|
57
|
+
end
|
58
|
+
|
59
|
+
g.on("--container CONTAINER_NAME", "a kubernetes container you'd like to visit") do |v|
|
60
|
+
options[:container_name] = v
|
61
|
+
end
|
62
|
+
|
63
|
+
g.on("-l", "--local-filepath FILEPATH", "file you'd like to copy") do |v|
|
64
|
+
options[:local_filepath] = v
|
65
|
+
end
|
66
|
+
|
67
|
+
g.on("-r", "--remote-path PATH", "path to file you'd like to copy to") do |v|
|
68
|
+
options[:remote_path] = v
|
69
|
+
end
|
70
|
+
|
71
|
+
g.on("-x", "use magic tools context") do |v|
|
72
|
+
options[:ktx] = v
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Run
|
78
|
+
#
|
79
|
+
|
80
|
+
global.parse(ARGV)
|
81
|
+
|
82
|
+
# set pod and service
|
83
|
+
set_context_namespace_deployment_pod_container_options(options)
|
84
|
+
set_ktx(options)
|
85
|
+
|
86
|
+
# display full command
|
87
|
+
write_history("""#{@cl_cmd_name} \\
|
88
|
+
--context=#{options[:kube_context]} \\
|
89
|
+
--namespace=#{options[:namespace]} \\
|
90
|
+
--deployment=#{options[:deployment_name]} \\
|
91
|
+
--pod=#{options[:pod_name]} \\
|
92
|
+
--container=#{options[:container_name]} \\
|
93
|
+
--local-filepath=#{options[:local_filepath]} \\
|
94
|
+
--remote-path=#{options[:remote_path]}
|
95
|
+
""")
|
96
|
+
|
97
|
+
@working_dir = ENV['CL_WORKING_DIR']
|
98
|
+
|
99
|
+
upload_file(options)
|
@@ -0,0 +1,120 @@
|
|
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 describe_selected_deployment(deployment, options)
|
21
|
+
@logger.puts ""
|
22
|
+
deployment_json = describe_deployment(options[:namespace], deployment)
|
23
|
+
git_project = deployment_json["metadata"]["annotations"]["git_project"]
|
24
|
+
git_commit = deployment_json["metadata"]["annotations"]["git_commit"]
|
25
|
+
|
26
|
+
pastel = Pastel.new
|
27
|
+
@logger.puts pastel.green("git_project:"), git_project
|
28
|
+
@logger.puts pastel.green("git_commit:"), git_commit
|
29
|
+
end
|
30
|
+
|
31
|
+
def describe_selected_pods(selected_pods, options)
|
32
|
+
pastel = Pastel.new
|
33
|
+
selected_pods.each do |selected_pod|
|
34
|
+
pod_name = selected_pod.first
|
35
|
+
@logger.puts ""
|
36
|
+
pod = describe_pod(options[:namespace], selected_pod)
|
37
|
+
host_ip = pod["status"]["hostIP"]
|
38
|
+
|
39
|
+
@logger.puts pastel.green("pod:"), pod_name, "(#{host_ip})"
|
40
|
+
pod["status"]["containerStatuses"].collect do |container|
|
41
|
+
image = container["image"]
|
42
|
+
image_parts = image.split(":").last.split('-')
|
43
|
+
@logger.puts pastel.green("image:"), image
|
44
|
+
|
45
|
+
if image_parts.count == 2
|
46
|
+
@logger.puts pastel.green("git_commit:"), image_parts.first
|
47
|
+
@logger.puts pastel.green("jenkins_build:"), image_parts.last
|
48
|
+
end
|
49
|
+
state = container["state"]
|
50
|
+
status = state.keys.first
|
51
|
+
started_at = state[status]['startedAt']
|
52
|
+
@logger.puts pastel.dim(status, " - ", started_at)
|
53
|
+
puts ""
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Options
|
61
|
+
#
|
62
|
+
|
63
|
+
options = {}
|
64
|
+
global_banner = <<DOC
|
65
|
+
|
66
|
+
Get build details on a deployment in google cloud
|
67
|
+
|
68
|
+
Usage: #{@cl_cmd_name} [filter-name] [options]
|
69
|
+
|
70
|
+
DOC
|
71
|
+
|
72
|
+
global = OptionParser.new do |g|
|
73
|
+
g.banner = global_banner
|
74
|
+
|
75
|
+
g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
|
76
|
+
options[:kube_context] = v
|
77
|
+
end
|
78
|
+
|
79
|
+
g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
|
80
|
+
options[:namespace] = v
|
81
|
+
end
|
82
|
+
|
83
|
+
g.on("-d", "--deployment NAME", "a kubernetes deployment name") do |v|
|
84
|
+
options[:deployment] = v
|
85
|
+
end
|
86
|
+
|
87
|
+
g.on("-p", "--pods PODS", "a csv of kubernetes pod names") do |v|
|
88
|
+
options[:pod_names] = v
|
89
|
+
end
|
90
|
+
|
91
|
+
g.on("-x", "use magic tools context") do |v|
|
92
|
+
options[:ktx] = v
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Run
|
98
|
+
#
|
99
|
+
|
100
|
+
global.parse(ARGV)
|
101
|
+
|
102
|
+
# set: context and namespace
|
103
|
+
set_context_and_namespace(options)
|
104
|
+
set_ktx(options)
|
105
|
+
|
106
|
+
# pick: deployment and pods
|
107
|
+
deployment = pick_kubectl_deployment(options)
|
108
|
+
pods = pick_kubectl_pods(deployment, options)
|
109
|
+
|
110
|
+
# display full command
|
111
|
+
write_history("""#{@cl_cmd_name} \\
|
112
|
+
--context=#{options[:kube_context]} \\
|
113
|
+
--namespace=#{options[:namespace]} \\
|
114
|
+
--deployment=#{deployment.first} \\
|
115
|
+
--pods=#{pods.collect(&:first).join(',')}
|
116
|
+
""")
|
117
|
+
|
118
|
+
# describe: deployment & pods
|
119
|
+
describe_selected_deployment(deployment, options)
|
120
|
+
describe_selected_pods(pods, options)
|
@@ -0,0 +1,60 @@
|
|
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
|
+
#
|
21
|
+
# Options
|
22
|
+
#
|
23
|
+
|
24
|
+
options = {}
|
25
|
+
global_banner = <<DOC
|
26
|
+
|
27
|
+
Set kube context
|
28
|
+
|
29
|
+
Usage: #{@cl_cmd_name} [filter-name] [options]
|
30
|
+
|
31
|
+
DOC
|
32
|
+
|
33
|
+
global = OptionParser.new do |g|
|
34
|
+
g.banner = global_banner
|
35
|
+
add_help_and_verbose(g)
|
36
|
+
|
37
|
+
g.on("-c", "--context CONTEXT", "a kubectl context name") do |v|
|
38
|
+
options[:kube_context] = v
|
39
|
+
end
|
40
|
+
|
41
|
+
g.on("-n", "--namespace NAMESPACE", "a kubectl namespace in the current context's cluster") do |v|
|
42
|
+
options[:namespace] = v
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Run
|
48
|
+
#
|
49
|
+
|
50
|
+
global.parse(ARGV)
|
51
|
+
|
52
|
+
# set: context and namespace
|
53
|
+
set_context_and_namespace(options)
|
54
|
+
set_ktx(options)
|
55
|
+
|
56
|
+
# display full command
|
57
|
+
write_history("""#{@cl_cmd_name} \\
|
58
|
+
--context=#{options[:kube_context]} \\
|
59
|
+
--namespace=#{options[:namespace]}
|
60
|
+
""")
|
@@ -0,0 +1,114 @@
|
|
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, pods, containers)
|
20
|
+
cmd = "kubectl stern '#{pods.collect(&:first).join('|')}' --context #{options[:kube_context]} --namespace #{options[:namespace]} --container '#{containers.collect(&:first).join('|')}' --since #{options[:since]} --container-state 'running,waiting,terminated'"
|
21
|
+
cmd += " | grep #{options[:grep]}" if options[:grep]
|
22
|
+
|
23
|
+
@logger.puts
|
24
|
+
@logger.wait cmd
|
25
|
+
exec(cmd) unless options[:dry_run]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Options
|
30
|
+
#
|
31
|
+
|
32
|
+
options = { since: '60m'}
|
33
|
+
global_banner = <<DOC
|
34
|
+
|
35
|
+
A sandbox to try things
|
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 NAME", "a kubernetes deployment name") do |v|
|
54
|
+
options[:deployment] = v
|
55
|
+
end
|
56
|
+
|
57
|
+
g.on("--pick-pods", "let me select specific pods") do |v|
|
58
|
+
options[:pick_pods] = v
|
59
|
+
end
|
60
|
+
|
61
|
+
g.on("--grep PATTERN", "grep for a pattern and only show those logs") do |v|
|
62
|
+
options[:grep] = v
|
63
|
+
end
|
64
|
+
|
65
|
+
g.on("--dry-run", "only show me the command") do |v|
|
66
|
+
options[:dry_run] = v
|
67
|
+
end
|
68
|
+
|
69
|
+
g.on("--since TIME", "Return logs newer than a relative duration like 52, 2m, or 3h. Defaults to `1m`") do |v|
|
70
|
+
options[:since] = v
|
71
|
+
end
|
72
|
+
|
73
|
+
g.on("-x", "use magic tools context") do |v|
|
74
|
+
options[:ktx] = v
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Run
|
81
|
+
#
|
82
|
+
|
83
|
+
global.parse(ARGV)
|
84
|
+
|
85
|
+
# set: context and namespace
|
86
|
+
set_context_and_namespace(options)
|
87
|
+
set_ktx(options)
|
88
|
+
|
89
|
+
# pick: deployment and pods
|
90
|
+
deployment = pick_kubectl_deployment(options)
|
91
|
+
if options[:pick_pods]
|
92
|
+
pods = pick_kubectl_pods(deployment, options)
|
93
|
+
else
|
94
|
+
# all pods
|
95
|
+
selector = deployment.last # last field is a selector
|
96
|
+
pods = get_kubectl_pods(options[:namespace], selector).collect {|o| o.values_at(0,2)}
|
97
|
+
end
|
98
|
+
|
99
|
+
# pick: containers
|
100
|
+
uniq_containers = pods.collect do |pod|
|
101
|
+
get_containers_on_pod(options[:namespace], pod.first)
|
102
|
+
end.flatten(1).uniq
|
103
|
+
containers = pick_multiple_result(uniq_containers, "Pick containers", options[:container_names])
|
104
|
+
|
105
|
+
|
106
|
+
# display full command
|
107
|
+
write_history("""#{@cl_cmd_name} \\
|
108
|
+
--context=#{options[:kube_context]} \\
|
109
|
+
--namespace=#{options[:namespace]} \\
|
110
|
+
--deployment=#{deployment.first} \\
|
111
|
+
--grep=#{options[:grep]}
|
112
|
+
""")
|
113
|
+
|
114
|
+
do_work(options, pods, containers)
|