@@ -21,9 +21,12 @@ import (
21
21
"io"
22
22
"strings"
23
23
24
+ "github.com/pkg/errors"
24
25
"github.com/spf13/cobra"
25
26
"github.com/stern/stern/kubernetes"
27
+ "github.com/stern/stern/stern"
26
28
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29
+ clientset "k8s.io/client-go/kubernetes"
27
30
)
28
31
29
32
func runCompletion (shell string , cmd * cobra.Command , out io.Writer ) error {
@@ -119,7 +122,137 @@ func contextCompletionFunc(o *options) func(cmd *cobra.Command, args []string, t
119
122
}
120
123
}
121
124
125
+ // queryCompletionFunc is a completion function that completes a resource
126
+ // that match the toComplete prefix.
127
+ func queryCompletionFunc (o * options ) func (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
128
+ return func (_ * cobra.Command , _ []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
129
+ var comps []string
130
+ parts := strings .Split (toComplete , "/" )
131
+ if len (parts ) != 2 {
132
+ // list available resources in the form "<resource>/"
133
+ for _ , matcher := range stern .ResourceMatchers {
134
+ if strings .HasPrefix (matcher .Name (), toComplete ) {
135
+ comps = append (comps , matcher .Name ()+ "/" )
136
+ }
137
+ }
138
+ return comps , cobra .ShellCompDirectiveNoFileComp | cobra .ShellCompDirectiveNoSpace
139
+ }
140
+
141
+ // list available names in the resources in the form "<resource>/<name>"
142
+ uniqueNamespaces := makeUnique (o .namespaces )
143
+ if o .allNamespaces || len (uniqueNamespaces ) > 1 {
144
+ // do not support multiple namespaces for simplicity
145
+ return compError (errors .New ("multiple namespaces are not supported" ))
146
+ }
147
+
148
+ clientConfig := kubernetes .NewClientConfig (o .kubeConfig , o .context )
149
+ clientset , err := kubernetes .NewClientSet (clientConfig )
150
+ if err != nil {
151
+ return compError (err )
152
+ }
153
+ var namespace string
154
+ if len (uniqueNamespaces ) == 1 {
155
+ namespace = uniqueNamespaces [0 ]
156
+ } else {
157
+ n , _ , err := clientConfig .Namespace ()
158
+ if err != nil {
159
+ return compError (err )
160
+ }
161
+ namespace = n
162
+ }
163
+
164
+ kind , name := parts [0 ], parts [1 ]
165
+ names , err := retrieveNamesFromResource (context .TODO (), clientset , namespace , kind )
166
+ if err != nil {
167
+ return compError (err )
168
+ }
169
+ for _ , n := range names {
170
+ if strings .HasPrefix (n , name ) {
171
+ comps = append (comps , kind + "/" + n )
172
+ }
173
+ }
174
+ return comps , cobra .ShellCompDirectiveNoFileComp
175
+ }
176
+ }
177
+
122
178
func compError (err error ) ([]string , cobra.ShellCompDirective ) {
123
179
cobra .CompError (err .Error ())
124
180
return nil , cobra .ShellCompDirectiveError
125
181
}
182
+
183
+ func retrieveNamesFromResource (ctx context.Context , client clientset.Interface , namespace , kind string ) ([]string , error ) {
184
+ opt := metav1.ListOptions {}
185
+ var names []string
186
+ switch {
187
+ // core
188
+ case stern .PodMatcher .Matches (kind ):
189
+ l , err := client .CoreV1 ().Pods (namespace ).List (ctx , opt )
190
+ if err != nil {
191
+ return nil , err
192
+ }
193
+ for _ , item := range l .Items {
194
+ names = append (names , item .GetName ())
195
+ }
196
+ case stern .ReplicationControllerMatcher .Matches (kind ):
197
+ l , err := client .CoreV1 ().ReplicationControllers (namespace ).List (ctx , opt )
198
+ if err != nil {
199
+ return nil , err
200
+ }
201
+ for _ , item := range l .Items {
202
+ names = append (names , item .GetName ())
203
+ }
204
+ case stern .ServiceMatcher .Matches (kind ):
205
+ l , err := client .CoreV1 ().Services (namespace ).List (ctx , opt )
206
+ if err != nil {
207
+ return nil , err
208
+ }
209
+ for _ , item := range l .Items {
210
+ names = append (names , item .GetName ())
211
+ }
212
+ // apps
213
+ case stern .DeploymentMatcher .Matches (kind ):
214
+ l , err := client .AppsV1 ().Deployments (namespace ).List (ctx , opt )
215
+ if err != nil {
216
+ return nil , err
217
+ }
218
+ for _ , item := range l .Items {
219
+ names = append (names , item .GetName ())
220
+ }
221
+ case stern .DaemonSetMatcher .Matches (kind ):
222
+ l , err := client .AppsV1 ().DaemonSets (namespace ).List (ctx , opt )
223
+ if err != nil {
224
+ return nil , err
225
+ }
226
+ for _ , item := range l .Items {
227
+ names = append (names , item .GetName ())
228
+ }
229
+ case stern .ReplicaSetMatcher .Matches (kind ):
230
+ l , err := client .AppsV1 ().ReplicaSets (namespace ).List (ctx , opt )
231
+ if err != nil {
232
+ return nil , err
233
+ }
234
+ for _ , item := range l .Items {
235
+ names = append (names , item .GetName ())
236
+ }
237
+ case stern .StatefulSetMatcher .Matches (kind ):
238
+ l , err := client .AppsV1 ().StatefulSets (namespace ).List (ctx , opt )
239
+ if err != nil {
240
+ return nil , err
241
+ }
242
+ for _ , item := range l .Items {
243
+ names = append (names , item .GetName ())
244
+ }
245
+ // batch
246
+ case stern .JobMatcher .Matches (kind ):
247
+ l , err := client .BatchV1 ().Jobs (namespace ).List (ctx , opt )
248
+ if err != nil {
249
+ return nil , err
250
+ }
251
+ for _ , item := range l .Items {
252
+ names = append (names , item .GetName ())
253
+ }
254
+ default :
255
+ return nil , fmt .Errorf ("resource type %s is not supported" , kind )
256
+ }
257
+ return names , nil
258
+ }
0 commit comments