cl-magic 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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)