@@ -11,6 +11,7 @@ import (
1111 "time"
1212
1313 "github.com/olekukonko/tablewriter"
14+ yaml "gopkg.in/yaml.v2"
1415 v1 "k8s.io/api/apps/v1"
1516 corev1 "k8s.io/api/core/v1"
1617)
@@ -208,6 +209,210 @@ func DescribePods(pod *corev1.Pod) {
208209 fmt .Printf ("Node Name: \t %s\n " , pod .Spec .NodeName )
209210}
210211
212+ func DescribePodsDetail (pod * corev1.Pod ) {
213+ var (
214+ container_port string
215+ state string
216+ )
217+
218+ // Print detailed information about the pod
219+ fmt .Printf ("Name: \t %s\n " , pod .ObjectMeta .Name )
220+ fmt .Printf ("Namespace: \t %s\n " , pod .ObjectMeta .Namespace )
221+ fmt .Printf ("Priority: \t %d\n " , pod .Spec .Priority )
222+ fmt .Printf ("Node: \t %s\n " , pod .Spec .NodeName )
223+ fmt .Printf ("Start Time:\t %s\n " , pod .Status .StartTime .Time )
224+
225+ // Convert labels to YAML
226+ labelsYAML , err := yaml .Marshal (pod .ObjectMeta .Labels )
227+ if err != nil {
228+ fmt .Println ("Error marshaling labels to YAML:" , err )
229+ } else {
230+ fmt .Printf ("Labels:" )
231+ yamlLines := strings .Split (string (labelsYAML ), "\n " )
232+ for _ , line := range yamlLines {
233+ fmt .Printf ("\t \t %s\n " , line )
234+ }
235+ }
236+ fmt .Printf ("Annotations:" )
237+ for key , value := range pod .ObjectMeta .Annotations {
238+ fmt .Printf ("\t %s: %s\n " , key , value )
239+ }
240+ fmt .Printf ("Status: \t %s\n " , pod .Status .Phase )
241+ fmt .Printf ("IP: \t %s\n " , pod .Status .PodIP )
242+
243+ fmt .Printf ("IPs:\n " )
244+ for _ , podIP := range pod .Status .PodIPs {
245+ fmt .Printf (" IP: \t \t %s\n " , podIP .IP )
246+ }
247+ fmt .Printf ("Controlled By: \t %s/%s\n " , pod .ObjectMeta .OwnerReferences [0 ].Kind , pod .ObjectMeta .OwnerReferences [0 ].Name )
248+ fmt .Println ("---------------------------------------------------------------------------" )
249+ fmt .Println ("Containers:" )
250+ for _ , container := range pod .Spec .Containers {
251+
252+ containerStatus := GetContainerStatus (pod , container .Name )
253+ if containerStatus != nil {
254+ fmt .Printf (" %s:\n " , container .Name )
255+ fmt .Printf (" Container ID: \t %s\n " , containerStatus .ContainerID )
256+ fmt .Printf (" Image: \t %s\n " , container .Image )
257+ fmt .Printf (" Image ID: \t %s\n " , containerStatus .ImageID )
258+
259+ if container .Ports != nil {
260+ fmt .Printf (" Port: \t \t %v\n " , container .Ports )
261+ } else {
262+ container_port = "<none>"
263+ fmt .Printf (" Port: \t \t %v\n " , container_port )
264+ }
265+
266+ if len (pod .Spec .Containers [0 ].Ports ) > 0 {
267+ if pod .Spec .Containers [0 ].Ports [0 ].HostPort != 0 {
268+ fmt .Printf (" Host Port: \t \t %d\n " , pod .Spec .Containers [0 ].Ports [0 ].HostPort )
269+ } else {
270+ fmt .Printf (" Host Port: \t \t <none>\n " )
271+ }
272+ } else {
273+ fmt .Printf (" Host Port: \t \t <none>\n " )
274+ }
275+
276+ if pod .Status .ContainerStatuses [0 ].State .Running != nil {
277+ state = "Running"
278+ } else if pod .Status .ContainerStatuses [0 ].State .Terminated != nil {
279+ state = "Terminated"
280+ } else {
281+ state = "Waiting"
282+ }
283+ fmt .Printf (" State: \t \t %s\n " , state )
284+ if pod .Status .ContainerStatuses [0 ].State .Running != nil {
285+ fmt .Printf (" Started: \t \t %s\n " , pod .Status .ContainerStatuses [0 ].State .Running .StartedAt .Time )
286+ }
287+
288+ if containerStatus .LastTerminationState .Terminated != nil {
289+ fmt .Printf (" Last State:\n " )
290+ fmt .Printf (" Reason: \t %s\n " , containerStatus .LastTerminationState .Terminated .Reason )
291+ fmt .Printf (" Exit Code: \t %d\n " , containerStatus .LastTerminationState .Terminated .ExitCode )
292+ fmt .Printf (" Started: \t %s\n " , containerStatus .LastTerminationState .Terminated .StartedAt .Time )
293+ fmt .Printf (" Finished: \t %s\n " , containerStatus .LastTerminationState .Terminated .FinishedAt .Time )
294+ }
295+
296+ fmt .Printf (" Ready: \t %t\n " , containerStatus .Ready )
297+ fmt .Printf (" Restart Count: \t %d\n " , containerStatus .RestartCount )
298+ fmt .Printf (" Limits:\n " )
299+ fmt .Printf (" cpu: %s\n " , container .Resources .Limits .Cpu ().String ())
300+ fmt .Printf (" memory: %s\n " , container .Resources .Limits .Memory ().String ())
301+ fmt .Printf (" Requests:\n " )
302+ fmt .Printf (" cpu: %s\n " , container .Resources .Requests .Cpu ().String ())
303+ fmt .Printf (" memory: %s\n " , container .Resources .Requests .Memory ().String ())
304+
305+ labelsYAML , err := yaml .Marshal (container .Env )
306+ if err != nil {
307+ fmt .Println ("Error marshaling environment variables to YAML:" , err )
308+ } else {
309+ fmt .Printf (" Environment:\n " )
310+ env := make ([]map [string ]interface {}, 0 )
311+ if err := yaml .Unmarshal (labelsYAML , & env ); err != nil {
312+ fmt .Println ("Error unmarshaling environment variables from YAML:" , err )
313+ } else {
314+ for _ , v := range env {
315+ name := v ["name" ].(string )
316+ value := v ["value" ].(string )
317+ fmt .Printf (" %s: %s\n " , name , value )
318+ }
319+ }
320+ }
321+
322+ fmt .Printf (" Mounts:\n " )
323+ for _ , mount := range container .VolumeMounts {
324+ fmt .Printf (" %s from %s (ro:%t)\n " , mount .MountPath , mount .Name , mount .ReadOnly )
325+ }
326+
327+ fmt .Println ("Conditions:" )
328+ fmt .Printf (" Type: \t \t Status\n " )
329+ for _ , cond := range pod .Status .Conditions {
330+ if cond .Type == "Initialized" {
331+ fmt .Printf (" %s\t \t %s\n " , cond .Type , cond .Status )
332+ }
333+ if cond .Type == "Ready" {
334+ fmt .Printf (" %s\t \t \t %s\n " , cond .Type , cond .Status )
335+ }
336+ if cond .Type == "ContainersReady" {
337+ fmt .Printf (" %s\t %s\n " , cond .Type , cond .Status )
338+ }
339+ if cond .Type == "PodScheduled" {
340+ fmt .Printf (" %s\t \t %s\n " , cond .Type , cond .Status )
341+ }
342+ }
343+
344+ fmt .Println ("Volumes:" )
345+ for _ , volume := range pod .Spec .Volumes {
346+ switch {
347+ case volume .ConfigMap != nil :
348+ fmt .Printf (" %s:\n " , volume .Name )
349+ fmt .Printf (" Type: ConfigMap\n " )
350+ fmt .Printf (" Name: %s\n " , volume .ConfigMap .Name )
351+ if volume .ConfigMap .Optional != nil {
352+ fmt .Printf (" Optional: %t\n " , * volume .ConfigMap .Optional )
353+ } else {
354+ fmt .Printf (" Optional: false\n " )
355+ }
356+ case volume .Secret != nil :
357+ fmt .Printf (" %s:\n " , volume .Name )
358+ fmt .Printf (" Type: Secret\n " )
359+ fmt .Printf (" Name: %s\n " , volume .Secret .SecretName )
360+ if volume .Secret .Optional != nil {
361+ fmt .Printf (" Optional: %t\n " , * volume .Secret .Optional )
362+ } else {
363+ fmt .Printf (" Optional: false\n " )
364+ }
365+ default :
366+ fmt .Printf (" %s: Unknown volume type\n " , volume .Name )
367+ }
368+ }
369+
370+ // QoS Class
371+ fmt .Printf ("QoS Class: \t \t %s\n " , pod .Status .QOSClass )
372+
373+ // Node Selectors
374+ nodeSelectors := "<none>"
375+ if len (pod .Spec .NodeSelector ) > 0 {
376+ nodeSelectors = fmt .Sprintf ("%v" , pod .Spec .NodeSelector )
377+ }
378+ fmt .Printf ("Node-Selectors: \t %s\n " , nodeSelectors )
379+ fmt .Printf ("\n " )
380+
381+ // Tolerations
382+ tolerations := pod .Spec .Tolerations
383+ tolerationStrings := make ([]string , 0 )
384+
385+ for _ , toleration := range tolerations {
386+ tolerationStrings = append (tolerationStrings , fmt .Sprintf ("%s:%s op=%s for %ds" , toleration .Key , toleration .Operator , toleration .Effect , toleration .TolerationSeconds ))
387+ }
388+ tolerationsString := strings .Join (tolerationStrings , "\n \t \t " )
389+ fmt .Printf ("Tolerations:\t %s\n " , strings .ReplaceAll (fmt .Sprintf ("%v" , tolerationsString ), " " , "\t " ))
390+
391+ // Events
392+ events := "<none>"
393+ fmt .Println ("Events:" )
394+ if len (pod .Status .Conditions ) > 0 {
395+ events = ""
396+ for _ , condition := range pod .Status .Conditions {
397+ fmt .Printf (" %-16s %v\n " , condition .Type , condition .Status )
398+ fmt .Printf (" Last Timestamp: %v\n " , condition .LastTransitionTime )
399+ }
400+ events = strings .TrimSuffix (events , ", " )
401+ }
402+ fmt .Printf ("\t %s\n " , events )
403+ }
404+ }
405+ }
406+
407+ func GetContainerStatus (pod * corev1.Pod , containerName string ) * corev1.ContainerStatus {
408+ for _ , status := range pod .Status .ContainerStatuses {
409+ if status .Name == containerName {
410+ return & status
411+ }
412+ }
413+ return nil
414+ }
415+
211416func GetFreePort () (int , error ) {
212417 // listen on a random port
213418 l , err := net .Listen ("tcp" , "127.0.0.1:0" )
0 commit comments