Top Level Namespace

Defined Under Namespace

Modules: Cl, LoadRunner Classes: AIPrompt, AITextSplitter, Elastic, Hash, HelpPrinter, Jira, Milvus, OptionParser, PartsMerger, WorldSettings, YamlArgMunger

Constant Summary collapse

KTX_FILEPATH =

cl ktx

'.cl-ktx.json'

Instance Method Summary collapse

Instance Method Details

#add_help(opts) ⇒ Object



12
13
14
15
16
17
# File 'lib/cl/magic/common/common_options.rb', line 12

def add_help(opts)
  opts.on("-h", "--help") do
    puts opts
    exit
  end
end

#add_help_and_verbose(opts) ⇒ Object



3
4
5
6
# File 'lib/cl/magic/common/common_options.rb', line 3

def add_help_and_verbose(opts)
  add_verbose(opts)
  add_help(opts)
end

#add_verbose(opts) ⇒ Object



8
9
10
# File 'lib/cl/magic/common/common_options.rb', line 8

def add_verbose(opts)
  opts.on("-v", "--[no-]verbose")
end

#ask_and_store_option(options, key, question) ⇒ Object



19
20
21
22
23
# File 'lib/cl/magic/common/common_options.rb', line 19

def ask_and_store_option(options, key, question)
  if options[key].nil? or options[key].empty?
    options[key] = TTY::Prompt.new.ask(question)
  end
end

#check_gcloud_project(project) ⇒ Object



62
63
64
65
66
67
68
69
70
71
# File 'lib/cl/magic/common/gcloud.rb', line 62

def check_gcloud_project(project)
  command = "gcloud info"
  result = TTY::Command.new(:printer => :null).run(command)

  current_project = result.select {|line| line.include? 'Project'}.first.split(': ').last
  if current_project != "[#{current_project}]"
    @logger.warn "Incorrect gcloud project: #{current_project}"
    @logger.warn "Use `gcloud config set project #{project}` and try again."
  end
end

#describe_deployment(namespace, deployment) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/cl/magic/common/kubectl.rb', line 30

def describe_deployment(namespace, deployment)
  namespace_option = " --namespace=#{namespace}" if namespace
  command = "kubectl get deployment.apps -ojson #{deployment.first} #{namespace_option}"
  @logger.wait command
  result = TTY::Command.new(:printer => :null).run(command)
  return JSON.parse(result.out)
end

#describe_pod(namespace, pod) ⇒ Object

Kubectl DESCRIBE commands



22
23
24
25
26
27
28
# File 'lib/cl/magic/common/kubectl.rb', line 22

def describe_pod(namespace, pod)
  namespace_option = " --namespace=#{namespace}" if namespace
  command = "kubectl get pod -ojson #{pod.first} #{namespace_option}"
  @logger.wait command
  result = TTY::Command.new(:printer => :null).run(command)
  return JSON.parse(result.out)
end

#describe_service(namespace, service) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/cl/magic/common/kubectl.rb', line 38

def describe_service(namespace, service)
  namespace_option = " --namespace=#{namespace}" if namespace
  command = "kubectl get service -ojson #{service.first} #{namespace_option}"
  @logger.wait command
  result = TTY::Command.new(:printer => :null).run(command)
  return JSON.parse(result.out)
end

#get_containers_on_pod(namespace, pod_name) ⇒ Object



94
95
96
97
# File 'lib/cl/magic/common/kubectl.rb', line 94

def get_containers_on_pod(namespace, pod_name)
  command = "kubectl get pods #{pod_name} -o jsonpath='{.spec.containers[*].name}' --namespace #{namespace}"
  return TTY::Command.new(:printer => :null).run(command).out.strip.chomp.split(' ').collect {|v|[v]}
end

#get_current_gcloud_projectObject



18
19
20
21
# File 'lib/cl/magic/common/gcloud.rb', line 18

def get_current_gcloud_project()
  command = "gcloud config get-value project"
  return TTY::Command.new(:printer => :null).run(command).out.strip.chomp
end

#get_current_kubectl_contextObject



84
85
86
87
# File 'lib/cl/magic/common/kubectl.rb', line 84

def get_current_kubectl_context()
  command = "kubectl config current-context"
  return TTY::Command.new(:printer => :null).run(command).out.strip.chomp
end

#get_current_kubectl_namespaceObject



89
90
91
92
# File 'lib/cl/magic/common/kubectl.rb', line 89

def get_current_kubectl_namespace()
  command = "kubectl config view --minify --output 'jsonpath={..namespace}'; echo"
  return TTY::Command.new(:printer => :null).run(command).out.strip.chomp
end

#get_gcloud_projects(filter = nil) ⇒ Object

gcloud GET



11
12
13
14
15
16
# File 'lib/cl/magic/common/gcloud.rb', line 11

def get_gcloud_projects(filter=nil)
  filter_option = "--filter #{filter}" if filter
  command = "gcloud projects list #{filter_option}"
  error_message = "No gcloud projects?  Are you authenticated?"
  return parse_table_results(command, error_message)
end

#get_ktx(options) ⇒ Object



227
228
229
230
231
232
233
234
235
236
# File 'lib/cl/magic/common/kubectl.rb', line 227

def get_ktx(options)
  if options[:ktx]
    if(File.exist?(KTX_FILEPATH))
      file = File.read(KTX_FILEPATH)
      ktx_hash = JSON.parse(file)
      options[:kube_context] = ktx_hash['kube_context']
      options[:namespace] = ktx_hash['namespace']
    end
  end
end

#get_kubectl_contextsObject



78
79
80
81
82
# File 'lib/cl/magic/common/kubectl.rb', line 78

def get_kubectl_contexts()
  command = "kubectl config get-contexts"
  error_message = "Your kubectl has no contexts; talk to your team about this. :)"
  return parse_table_results(command, error_message)
end

#get_kubectl_deployments(namespace) ⇒ Object

Kubectl GET commands



50
51
52
53
54
55
# File 'lib/cl/magic/common/kubectl.rb', line 50

def get_kubectl_deployments(namespace)
  namespace_option = namespace ? " --namespace=#{namespace}" : " --all-namespaces"
  command = "kubectl get -o=wide deployment.apps #{namespace_option}"
  error_message = "No deployments found"
  return parse_table_results(command, error_message)
end

#get_kubectl_namespacesObject



72
73
74
75
76
# File 'lib/cl/magic/common/kubectl.rb', line 72

def get_kubectl_namespaces()
  command = "kubectl get namespaces"
  error_message = "No namespaces found in kubectl context: #{get_current_kubectl_context()}"
  return parse_table_results(command, error_message)
end

#get_kubectl_pods(namespace, selector) ⇒ Object



57
58
59
60
61
62
63
# File 'lib/cl/magic/common/kubectl.rb', line 57

def get_kubectl_pods(namespace, selector)
  selector_option = " --selector=#{selector}" if selector
  namespace_option = " --namespace=#{namespace}" if namespace
  command = "kubectl get pods #{selector_option} #{namespace_option}"
  error_message = "No pods found"
  return parse_table_results(command, error_message)
end

#get_kubectl_services(namespace) ⇒ Object



65
66
67
68
69
70
# File 'lib/cl/magic/common/kubectl.rb', line 65

def get_kubectl_services(namespace)
  namespace_option = " --namespace=#{namespace}" if namespace
  command = "kubectl get -o=wide services #{namespace_option}"
  error_message = "Your kubectl has no services; talk to your team about this. :)"
  return parse_table_results(command, error_message)
end

#get_loggerObject



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/cl/magic/common/logging.rb', line 3

def get_logger
  return TTY::Logger.new do |config|
    config.types = {
      puts: {level: :info},
    }
    config.handlers = [
      [:console, {
        styles: {
          puts: {
            symbol: "",
            label: "",
            color: :black,
            levelpad: 0
          },
        }
      }]
    ]
  end
end

#get_sql_databases(instance) ⇒ Object



33
34
35
36
# File 'lib/cl/magic/common/gcloud.rb', line 33

def get_sql_databases(instance)
  command = "gcloud sql databases list --instance=#{instance.first}"
  return parse_table_results(command, 'No sql databases. :(')
end

#get_sql_instancesObject



23
24
25
26
# File 'lib/cl/magic/common/gcloud.rb', line 23

def get_sql_instances()
  command = "gcloud sql instances list"
  return parse_table_results(command, 'No sql instances. :(')
end

#get_sql_users(instance) ⇒ Object



28
29
30
31
# File 'lib/cl/magic/common/gcloud.rb', line 28

def get_sql_users(instance)
  command = "gcloud sql users list --instance=#{instance.first}"
  return parse_table_results(command, 'No sql users. :(')
end

#get_users_kube_config_cmd_pathObject

Kubectl config commands



11
12
13
14
15
16
# File 'lib/cl/magic/common/kubectl.rb', line 11

def get_users_kube_config_cmd_path
  tty_command = TTY::Command.new(printer: :null)
  command = "grep cmd-path ~/.kube/config | head -n1 | cut -d ':' -f2"
  out, err = tty_command.run(command)
  return out.chomp.strip
end

#parse_table_results(command, error_message, num_headers = 1, split = nil, working_dir = nil) ⇒ Object

Parse table results

Many commands return

  • a table of results

  • the first row being headers

  • each following row space separated values

Lets assume this and parse the results



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/cl/magic/common/parse_and_pick.rb', line 13

def parse_table_results(command, error_message, num_headers=1, split=nil, working_dir=nil)
  results = []

  @logger.puts ""
  @logger.wait command

  # working directory?
  command = "cd #{working_dir} && #{command}" if working_dir

  # run command
  TTY::Command.new(:printer => :null).run(command).each { |line| results << line.split(split) }
  num_headers.times { results.delete_at(0) } # remove header

  if not results.any?
    @logger.error error_message
    exit(1)
  end
  return results
end

#pick_gcloud_project(filter = nil) ⇒ Object

Misc



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/cl/magic/common/gcloud.rb', line 42

def pick_gcloud_project(filter=nil)

  prev_project = get_current_gcloud_project()

  # pick content
  projects = get_gcloud_projects(filter)
  selected_project = pick_single_result(projects, 'Pick a project', nil, prev_project)

  # change context
  if selected_project.first != prev_project
    command = "gcloud config set project #{selected_project.first}"
    @logger.wait command
    TTY::Command.new(:printer => :null).run(command)
  else
    @logger.info "project already set to #{selected_project.first}"
  end

  return selected_project
end

#pick_kubectl_container(pod, options) ⇒ Object



181
182
183
184
185
# File 'lib/cl/magic/common/kubectl.rb', line 181

def pick_kubectl_container(pod, options)
  containers = get_containers_on_pod(options[:namespace], pod.first)
  container = pick_single_result(containers, "Pick container", options[:container_name])
  options[:container_name] = container.first
end

#pick_kubectl_context(selected_context = nil) ⇒ Object

Kubectl pickers



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/cl/magic/common/kubectl.rb', line 103

def pick_kubectl_context(selected_context=nil)

  prev_context = get_current_kubectl_context()

  # pick content
  if selected_context.nil?
    selected_context = TTY::Prompt.new(interrupt: :exit).select("Which context?", filter: true, per_page: 20) do |menu|
      get_kubectl_contexts().each do |context|
        if context[0]=="*"
          menu.default context[1]
          menu.choice context[1], context[1]
        else
          menu.choice context[0], context[0]
        end
      end
    end
  end

  # change context
  if selected_context != prev_context
    command = "kubectl config use-context #{selected_context}"
    @logger.wait command
    TTY::Command.new(:printer => :null).run(command)
  end

  return selected_context
end

#pick_kubectl_deployment(options) ⇒ Object



131
132
133
134
135
136
137
138
139
# File 'lib/cl/magic/common/kubectl.rb', line 131

def pick_kubectl_deployment(options)
  deploments = get_kubectl_deployments(options[:namespace]).collect {|o| o.values_at(0,-1)}
  deployment = pick_single_result(deploments, "Which deployment?", options[:deployment_name])
  if deployment.nil? or deployment.last == '<none>'
    @logger.error "No deployments found"
    exit(1)
  end
  return deployment
end

#pick_kubectl_namespace(options) ⇒ Object



141
142
143
144
145
# File 'lib/cl/magic/common/kubectl.rb', line 141

def pick_kubectl_namespace(options)
  namespaces = get_kubectl_namespaces().collect {|o| o.values_at(0)}
  current_namespace = get_current_kubectl_namespace()
  return pick_single_result(namespaces, "Which namespace?", options[:namespace], current_namespace)
end

#pick_kubectl_pod(service, options) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/cl/magic/common/kubectl.rb', line 169

def pick_kubectl_pod(service, options)
  selector = service.last # last field is a selector
  pods = get_kubectl_pods(options[:namespace], selector)
  selected_pod = pick_single_result(pods, "Which pods?", options[:pod_name])

  if selected_pod.nil?
    @logger.error "service #{service.first} has no pod."
    exit(1)
  end
  return selected_pod
end

#pick_kubectl_pods(deployment, options) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/cl/magic/common/kubectl.rb', line 157

def pick_kubectl_pods(deployment, options)
  selector = deployment.last # last field is a selector
  pods = get_kubectl_pods(options[:namespace], selector)
  selected_pods = pick_multiple_result(pods, "Which pods?", options[:pod_names])

  if selected_pods.count == 0
    @logger.warn "deployment #{deployment.last} has no pods."
    exit()
  end
  return selected_pods
end

#pick_kubectl_service(options) ⇒ Object



147
148
149
150
151
152
153
154
155
# File 'lib/cl/magic/common/kubectl.rb', line 147

def pick_kubectl_service(options)
  services = get_kubectl_services(options[:namespace]).collect {|o| o.values_at(0,-1)}
  service = pick_single_result(services, "Pick service", options[:service_name])
  if service.nil? or service.last == '<none>'
    @logger.error "No services found"
    exit(1)
  end
  return service
end

#pick_multiple_result(results, prompt_message, exacts = nil, echo = true, default = []) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/cl/magic/common/parse_and_pick.rb', line 66

def pick_multiple_result(results, prompt_message, exacts=nil, echo=true, default=[])

  # exact match?
  return results.select {|r| exacts.split(',').include? r.first} if exacts

  # 0 or 1 result?
  return results if results.count < 2

  selections = TTY::Prompt.new(interrupt: :exit).multi_select(prompt_message, filter: true, per_page: 20, echo: echo) do |menu|
    # add choices
    results.each do |result|
      menu.choice result.join(' | '), result.first
    end

    # defaults
    keys = results.collect {|r|r.first}
    default_indexes = default.map {|d| keys.index(d) + 1}
    if default.any?
      menu.default *default_indexes
    end
  end

  return results.select {|r| selections.include? r.first}
end

#pick_single_result(results, prompt_message, exact = nil, default = nil, selection_index = 0) ⇒ Object

Prompt the user to pick a single result

results - and array of arrays prompt_message - the message for our picker exact - if provided, we’ll return whatever matches this exactly default - if provided, the picker will default to this item



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/cl/magic/common/parse_and_pick.rb', line 43

def pick_single_result(results, prompt_message, exact=nil, default=nil, selection_index=0)

  # exact match?
  results = results.select {|r| r[selection_index] == exact} if exact

  case results.count
  when 0  # no results?
    return nil
  when 1  # one result, just return it
    return results.first
  end

  # prompt many results
  selection = TTY::Prompt.new(interrupt: :exit).select(prompt_message, filter: true, per_page: 20) do |menu|
    results.each do |result|
      menu.default result.join(' | ') if result[selection_index] == default
      menu.choice result.join(' | '), result[selection_index]
    end
  end
  return results.select { |r| r[selection_index]==selection }.first
end

#set_context_and_namespace(options) ⇒ Object



203
204
205
206
207
208
209
210
211
# File 'lib/cl/magic/common/kubectl.rb', line 203

def set_context_and_namespace(options)
  get_ktx(options) if options[:ktx]

  # set: context and namespace
  if options[:kube_context].nil? and options[:namespace].nil?
    options[:kube_context] = pick_kubectl_context(options[:kube_context]) if options[:kube_context].nil?
    options[:namespace] = pick_kubectl_namespace(options).first if options[:namespace].nil? # just the name
  end
end

#set_context_namespace_deployment_pod_container_options(options) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/cl/magic/common/kubectl.rb', line 187

def set_context_namespace_deployment_pod_container_options(options)
  # set: context and namespace
  set_context_and_namespace(options)

  # pick: deployment and pod
  deployment = pick_kubectl_deployment(options)
  pod = pick_kubectl_pod(deployment, options)

  # set options
  options[:deployment_name] = deployment.first
  options[:pod_name] = pod.first

  # set container
  pick_kubectl_container(pod, options)
end

#set_ktx(options) ⇒ Object



218
219
220
221
222
223
224
225
# File 'lib/cl/magic/common/kubectl.rb', line 218

def set_ktx(options)
  File.open(KTX_FILEPATH, "w") do |f|
    f.write({
      kube_context: options[:kube_context],
      namespace: options[:namespace],
    }.to_json)
  end
end

#write_history(message) ⇒ Object



23
24
25
# File 'lib/cl/magic/common/logging.rb', line 23

def write_history(message)
  File.open("#{Dir.home}/.cl_history", "a") {|f| f.puts message }
end