@@ -35,7 +35,7 @@ module ClusterTools
3535 end
3636
3737 def self.ensure_namespace_exists !
38- namespaces = KubectlClient ::Get .namespaces( )
38+ namespaces = KubectlClient ::Get .resource( " namespaces " )
3939 namespace_array = namespaces[" items" ].as_a
4040
4141 Log .debug { " ClusterTools ensure_namespace_exists namespace_array: #{ namespace_array } " }
@@ -68,72 +68,59 @@ module ClusterTools
6868
6969 KubectlClient ::Delete .file(" cluster_tools.yml" , namespace: self .namespace!)
7070 # todo make this work with cluster-tools-host-namespace
71- KubectlClient ::Get .resource_wait_for_uninstall(" Daemonset" , " cluster-tools" , namespace: self .namespace!)
71+ KubectlClient ::Wait .resource_wait_for_uninstall(" Daemonset" , " cluster-tools" , namespace: self .namespace!)
7272 end
7373
74- def self.exec (cli : String )
74+ def self.exec (cli : String ) : KubectlClient :: CMDResult
7575 # todo change to get all pods, schedulable nodes is slow
7676 pods = KubectlClient ::Get .pods_by_nodes(KubectlClient ::Get .schedulable_nodes_list)
77- pods = KubectlClient ::Get .pods_by_label (pods, " name" , " cluster-tools" )
77+ pods = KubectlClient ::Get .pods_by_labels (pods, { " name" => " cluster-tools" } )
7878
7979 cluster_tools_pod_name = pods[0 ].dig?(" metadata" , " name" ) if pods[0 ]?
8080 Log .info { " cluster_tools_pod_name: #{ cluster_tools_pod_name } " }
8181
82- cmd = " #{ cluster_tools_pod_name } -- #{ cli } "
83- KubectlClient .exec(cmd, namespace: self .namespace!)
82+ KubectlClient ::Utils .exec(cluster_tools_pod_name, cli, namespace: self .namespace!)
8483 end
8584
85+ def self.exec_by_node (cli : String , node_name : String ) : KubectlClient ::CMDResult ?
86+ Log .info { " exec_by_node: Called with String" }
8687
87- def self.exec_by_node_construct_cli (cli : String , node : JSON ::Any )
88- pods = KubectlClient ::Get .pods_by_nodes([node])
89- # pods = KubectlClient::Get.pods_by_label(pods, "name", "cluster-tools-k8s")
90- pods = KubectlClient ::Get .pods_by_label(pods, " name" , " cluster-tools" )
91-
92- cluster_tools_pod_name = pods[0 ].dig?(" metadata" , " name" ) if pods[0 ]?
93- Log .debug { " cluster_tools_pod_name: #{ cluster_tools_pod_name } " }
88+ nodes = KubectlClient ::Get .resource(" nodes" )[" items" ].as_a
9489
95- full_cli = " #{ cluster_tools_pod_name } -- #{ cli } "
96- Log .debug { " ClusterTools exec full cli: #{ full_cli } " }
97- return full_cli
98- end
90+ node : JSON ::Any | Nil
91+ node = nodes.find{ |n | n.dig?(" metadata" , " name" ) == node_name }
9992
100- def self.exec_by_node (cli : String , nodeName : String )
101- Log .info { " exec_by_node: Called with String" }
93+ return self .exec_by_node(cli, node) if node
10294
103- nodes = KubectlClient ::Get .nodes[" items" ].as_a
95+ Log .error { " exec_by_node failed, '#{ node_name } ' not matched to any existing nodes" }
96+ nil
97+ end
98+
99+ private def self.get_cluster_tools_pod_on_node (node : JSON ::Any )
100+ pods = KubectlClient ::Get .pods_by_nodes([node])
101+ pods = KubectlClient ::Get .pods_by_labels(pods, {" name" => " cluster-tools" })
104102
105- node : JSON :: Any | Nil
106- node = nodes.find{ | n | n.dig?( " metadata " , " name " ) == nodeName }
103+ cluster_tools_pod_name = pods[ 0 ].dig?( " metadata " , " name " ) if pods[ 0 ]?
104+ Log .debug { " cluster_tools_pod_name: #{ cluster_tools_pod_name } " }
107105
108- if node
109- self .exec_by_node(cli, node)
110- else
111- " "
112- end
106+ cluster_tools_pod_name
113107 end
114-
115108
116- def self.exec_by_node (cli : String , node : JSON ::Any )
109+ def self.exec_by_node (cli : String , node : JSON ::Any ) : KubectlClient :: CMDResult
117110 Log .info { " exec_by_node: Called with JSON" }
118- # todo change to get all pods, schedulable nodes is slow
119-
120- # pods_by_nodes internally use KubectlClient::Get.pods which uses --all-namespaces option.
121- # So they do not have to be passed the namespace to perform operations.
122- full_cli = exec_by_node_construct_cli(cli, node)
123- exec = KubectlClient .exec(full_cli, namespace: self .namespace)
111+ # 'pods_by_nodes' fetches pods from all namespaces so they
112+ # do not have to be passed the namespace to perform operations.
113+ pod_name = get_cluster_tools_pod_on_node(node)
114+ exec = KubectlClient ::Utils .exec(pod_name, cli, namespace: self .namespace)
124115 Log .debug { " ClusterTools exec: #{ exec } " }
125116 exec
126117 end
127118
128- def self.exec_by_node_bg (cli : String , node : JSON ::Any )
129- # todo change to get all pods, schedulable nodes is slow
130-
131- # pods_by_nodes internally use KubectlClient::Get.pods which uses --all-namespaces option.
132- # So they do not have to be passed the namespace to perform operations.
133-
134- full_cli = exec_by_node_construct_cli(cli, node)
135- Log .debug { " ClusterTools exec full cli: #{ full_cli } " }
136- exec = KubectlClient .exec_bg(full_cli, namespace: self .namespace)
119+ def self.exec_by_node_bg (cli : String , node : JSON ::Any ) : KubectlClient ::BackgroundCMDResult
120+ # 'pods_by_nodes' fetches pods from all namespaces so they
121+ # do not have to be passed the namespace to perform operations.
122+ pod_name = get_cluster_tools_pod_on_node(node)
123+ exec = KubectlClient ::Utils .exec_bg(pod_name, cli, namespace: self .namespace)
137124 Log .debug { " ClusterTools exec: #{ exec } " }
138125 exec
139126 end
@@ -152,13 +139,13 @@ module ClusterTools
152139 Log .info {" node_pid_by_container_id container_id: #{ container_id } " }
153140 short_container_id = parse_container_id(container_id)
154141 inspect = ClusterTools .exec_by_node(" crictl inspect #{ short_container_id } " , node)
155- Log .debug {" node_pid_by_container_id inspect: #{ inspect[:output ] } " }
156- if inspect[:status ].success?
157- pid = " #{ JSON .parse(inspect[:output ]).dig?(" info" , " pid" )} "
158- else
142+ unless inspect[:status ].success?
159143 Log .error {" container_id not found for: #{ container_id } " }
160- pid = nil
144+ return nil
161145 end
146+
147+ Log .debug {" node_pid_by_container_id inspect: #{ inspect[:output ] } " }
148+ pid = " #{ JSON .parse(inspect[:output ]).dig?(" info" , " pid" )} "
162149 Log .info {" node_pid_by_container_id pid: #{ pid } " }
163150 pid
164151 end
@@ -168,7 +155,7 @@ module ClusterTools
168155 case kind
169156 when " deployment" ," statefulset" ," pod" ," replicaset" , " daemonset"
170157 resource_yaml = KubectlClient ::Get .resource(resource[:kind ], resource[:name ], resource[:namespace ])
171- pods = KubectlClient ::Get .pods_by_resource (resource_yaml, resource[:namespace ])
158+ pods = KubectlClient ::Get .pods_by_resource_labels (resource_yaml, resource[:namespace ])
172159 pid_log_names = [] of String
173160 pod_resp = pods.map do |pod |
174161 pod_name = pod.dig(" metadata" , " name" )
@@ -211,10 +198,17 @@ module ClusterTools
211198 node_name = node.dig(" metadata" , " name" ).as_s
212199 Log .info { " node name : #{ node_name } " }
213200 if only_container_pids
214- pids = KernelIntrospection ::K8s ::Node .pids_by_container(container_id, node)
215- else
216- pids = KernelIntrospection ::K8s ::Node .pids(node)
217- end
201+ pids = KernelIntrospection ::K8s ::Node .pids_by_container(container_id, node)
202+ else
203+ pids = KernelIntrospection ::K8s ::Node .pids(node)
204+ end
205+
206+ if pids.empty?
207+ Log .info { " pids empty #{ pids } " }
208+ false
209+ next
210+ end
211+
218212 Log .info { " parsed pids: #{ pids } " }
219213 proc_statuses = KernelIntrospection ::K8s ::Node .all_statuses_by_pids(pids, node)
220214
@@ -237,8 +231,7 @@ module ClusterTools
237231
238232 def self.wait_for_cluster_tools
239233 Log .info { " ClusterTools wait_for_cluster_tools" }
240- KubectlClient ::Get .resource_wait_for_install(" Daemonset" , " cluster-tools" , namespace: self .namespace!, wait_count: 300 )
241- # KubectlClient::Get.resource_wait_for_install("Daemonset", "cluster-tools-k8s", namespace: self.namespace)
234+ KubectlClient ::Wait .resource_wait_for_install(" Daemonset" , " cluster-tools" , namespace: self .namespace!, wait_count: 300 )
242235 end
243236
244237 # https://windsock.io/explaining-docker-image-ids/
@@ -264,33 +257,56 @@ module ClusterTools
264257 JSON .parse(%( {}) )
265258 end
266259
267- def self.local_match_by_image_name (image_names : Array (String ), nodes= KubectlClient ::Get .nodes[" items" ].as_a )
260+ def self.local_match_by_image_name (image_names : Array (String ), nodes= KubectlClient ::Get .resource( " nodes" ) [" items" ].as_a )
268261 image_names.map{|x | local_match_by_image_name(x, nodes)}.flatten.find{|m |m[:found ]== true }
269262 end
270- def self.local_match_by_image_name (image_name, nodes= KubectlClient ::Get .nodes[" items" ].as_a )
263+ def self.local_match_by_image_name (image_name, nodes= KubectlClient ::Get .resource( " nodes" ) [" items" ].as_a )
271264 Log .info { " local_match_by_image_name image_name: #{ image_name } " }
272265 nodes = KubectlClient ::Get .nodes[" items" ].as_a
273266 local_match_by_image_name(image_name, nodes)
274267 end
275268
269+ # TODO (rafal-lal): add spec for it
276270 def self.local_match_by_image_name (image_name, nodes : Array (JSON ::Any ))
277271 Log .info { " local_match_by_image_name image_name: #{ image_name } " }
278272
279273 match = Hash {:found => false , :digest => " " , :release_name => " " }
280- # todo get name of pod and match against one pod instead of getting all pods and matching them
281- tag = KubectlClient ::Get .container_tag_from_image_by_nodes(image_name, nodes)
274+ # Group all imageIDs on passed 'nodes' into array.
275+ # If 'image_name' matches the name with tag, save its first occurence.
276+ # node.status.images is in following format:
277+ # {
278+ # "names": [
279+ # "registry.k8s.io/kube-state-metrics/kube-state-metrics@sha256:37d84129932.......",
280+ # "registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.14.0"
281+ # ],
282+ # "sizeBytes": 51212837
283+ # }
284+ tag = " "
285+ imageIDs = [] of String
286+ nodes.each do |node |
287+ begin
288+ images = node.dig(" status" , " images" ).as_a.each do |image |
289+ image.dig(" names" ).as_a.each do |name |
290+ if name.as_s.includes?(" sha256" )
291+ imageIDs << name.as_s
292+ else
293+ next unless name.as_s.includes?(image_name)
294+ tag = DockerClient .parse_image(name.as_s)[" tag" ] if tag.empty?
295+ end
296+ end
297+ end
298+ rescue
299+ next
300+ end
301+ end
282302
283- if tag
303+ if ! tag.empty?
284304 Log .info { " container tag: #{ tag } " }
285-
286- pods = KubectlClient ::Get .pods_by_nodes(nodes)
287-
288- # todo container_digests_by_pod (use pod from previous image search) --- performance enhancement
289- imageids = KubectlClient ::Get .container_digests_by_nodes(nodes)
290- resp = ClusterTools .official_content_digest_by_image_name(image_name + " :" + tag )
305+
306+ resp = ClusterTools .official_content_digest_by_image_name(image_name + " :" + tag)
291307 sha_list = [{" name" => image_name, " manifest_digest" => resp[" Digest" ].as_s}]
292308 Log .info { " jaeger_pods sha_list : #{ sha_list } " }
293- match = DockerClient ::K8s .local_digest_match(sha_list, imageids )
309+ match = DockerClient ::K8s .local_digest_match(sha_list, imageIDs )
294310 Log .info { " local_match_by_image_name match : #{ match } " }
295311 else
296312 Log .info { " local_match_by_image_name tag: #{ tag } match : #{ match } " }
@@ -299,14 +315,14 @@ module ClusterTools
299315 Log .info { " local_match_by_image_name match: #{ match } " }
300316 match
301317 end
302-
318+
303319 def self.pod_name ()
304- KubectlClient ::Get .pod_status (" cluster-tools" , namespace: self .namespace!).split( " , " )[ 0 ]
320+ KubectlClient ::Get .match_pods_by_prefix (" cluster-tools" , namespace: self .namespace!).first?
305321 end
306322
307323 def self.pod_by_node (node )
308324 resource = KubectlClient ::Get .resource(" Daemonset" , " cluster-tools" , namespace: self .namespace!)
309- pods = KubectlClient ::Get .pods_by_resource (resource, namespace: self .namespace!)
325+ pods = KubectlClient ::Get .pods_by_resource_labels (resource, namespace: self .namespace!)
310326 cluster_pod = pods.find do |pod |
311327 pod.dig(" spec" , " nodeName" ) == node
312328 end
0 commit comments