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,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)