github.com/inspektor-gadget/inspektor-gadget@v0.28.1/cmd/ig/containers/containers.go (about) 1 // Copyright 2022 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package containers 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "os" 21 "strings" 22 "time" 23 24 "github.com/moby/moby/pkg/stringid" 25 "github.com/spf13/cobra" 26 27 commonutils "github.com/inspektor-gadget/inspektor-gadget/cmd/common/utils" 28 "github.com/inspektor-gadget/inspektor-gadget/cmd/ig/utils" 29 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns" 30 containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" 31 igmanager "github.com/inspektor-gadget/inspektor-gadget/pkg/ig-manager" 32 "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host" 33 ) 34 35 const igSubKey = "ig-key" 36 37 func NewListContainersCmd() *cobra.Command { 38 var commonFlags utils.CommonFlags 39 var optionWatch bool 40 41 cmd := &cobra.Command{ 42 Use: "list-containers", 43 Short: "List all containers", 44 RunE: func(*cobra.Command, []string) error { 45 // The list-containers command is not a gadget, so the local 46 // runtime won't call host.Init(). 47 err := host.Init(host.Config{}) 48 if err != nil { 49 return err 50 } 51 52 igmanager, err := igmanager.NewManager(commonFlags.RuntimeConfigs) 53 if err != nil { 54 return commonutils.WrapInErrManagerInit(err) 55 } 56 defer igmanager.Close() 57 58 selector := containercollection.ContainerSelector{ 59 Runtime: containercollection.RuntimeSelector{ 60 ContainerName: commonFlags.Containername, 61 }, 62 } 63 64 if !optionWatch { 65 parser, err := commonutils.NewGadgetParserWithK8sAndRuntimeInfo(&commonFlags.OutputConfig, columnsWithAdjustedVisibility(containercollection.GetColumns())) 66 if err != nil { 67 return commonutils.WrapInErrParserCreate(err) 68 } 69 containers := igmanager.GetContainersBySelector(&selector) 70 71 parser.Sort(containers, []string{"runtime.runtimeName", "runtime.containerName"}) 72 if err = printContainers(parser, commonFlags, containers); err != nil { 73 return err 74 } 75 return nil 76 } 77 78 cols := columnsWithAdjustedVisibility(columns.MustCreateColumns[containercollection.PubSubEvent]()) 79 cols.SetExtractor("event", func(event *containercollection.PubSubEvent) any { 80 return event.Type.String() 81 }) 82 cols.MustSetExtractor("runtime.containerImageName", func(event *containercollection.PubSubEvent) any { 83 if event == nil || event.Container == nil { 84 return "" 85 } 86 if strings.Contains(event.Container.Runtime.ContainerImageName, "sha256") { 87 return stringid.TruncateID(event.Container.Runtime.ContainerImageName) 88 } 89 return event.Container.Runtime.ContainerImageName 90 }) 91 92 parser, err := commonutils.NewGadgetParserWithK8sAndRuntimeInfo(&commonFlags.OutputConfig, cols) 93 if err != nil { 94 return commonutils.WrapInErrParserCreate(err) 95 } 96 containers := igmanager.ContainerCollection.Subscribe( 97 igSubKey, 98 selector, 99 func(event containercollection.PubSubEvent) { 100 if err = printPubSubEvent(parser, commonFlags, &event); err != nil { 101 fmt.Fprintf(os.Stderr, "Warning: %s\n", err) 102 } 103 }, 104 ) 105 defer igmanager.ContainerCollection.Unsubscribe(igSubKey) 106 107 if commonFlags.OutputMode != commonutils.OutputModeJSON { 108 fmt.Println(parser.BuildColumnsHeader()) 109 } 110 timestamp := time.Now().Format(time.RFC3339) 111 for _, container := range containers { 112 e := containercollection.PubSubEvent{ 113 Timestamp: timestamp, 114 Type: containercollection.EventTypeAddContainer, 115 Container: container, 116 } 117 if err = printPubSubEvent(parser, commonFlags, &e); err != nil { 118 return err 119 } 120 } 121 122 utils.WaitForEnd(&commonFlags) 123 return nil 124 }, 125 } 126 127 cmd.Flags().BoolVarP( 128 &optionWatch, 129 "watch", "w", 130 false, 131 "After listing the containers, watch for new containers") 132 133 utils.AddCommonFlags(cmd, &commonFlags) 134 135 return cmd 136 } 137 138 func printContainers(parser *commonutils.GadgetParser[containercollection.Container], commonFlags utils.CommonFlags, containers []*containercollection.Container) error { 139 switch commonFlags.OutputMode { 140 case commonutils.OutputModeJSON: 141 b, err := json.MarshalIndent(containers, "", " ") 142 if err != nil { 143 return commonutils.WrapInErrMarshalOutput(err) 144 } 145 146 fmt.Printf("%s\n", b) 147 case commonutils.OutputModeColumns: 148 fmt.Println(parser.TransformIntoTable(containers)) 149 } 150 151 return nil 152 } 153 154 func printPubSubEvent(parser *commonutils.GadgetParser[containercollection.PubSubEvent], commonFlags utils.CommonFlags, event *containercollection.PubSubEvent) error { 155 switch commonFlags.OutputMode { 156 case commonutils.OutputModeJSON: 157 b, err := json.MarshalIndent(event, "", " ") 158 if err != nil { 159 return commonutils.WrapInErrMarshalOutput(err) 160 } 161 fmt.Printf("%s\n", b) 162 case commonutils.OutputModeColumns: 163 fmt.Println(parser.TransformIntoColumns(event)) 164 } 165 166 return nil 167 } 168 169 func columnsWithAdjustedVisibility[T containercollection.Container | containercollection.PubSubEvent](cols *columns.Columns[T]) *columns.Columns[T] { 170 for _, c := range cols.GetColumnMap(columns.WithTag("kubernetes")) { 171 c.Visible = false 172 } 173 for _, c := range cols.GetColumnMap(columns.WithTag("runtime")) { 174 c.Visible = true 175 } 176 return cols 177 }