This repository has been archived by the owner on Jan 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
minikubectl.go
188 lines (154 loc) · 5.46 KB
/
minikubectl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
Copyright 2021 GramLabs, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package scan
import (
"bytes"
"fmt"
"sync"
"github.com/spf13/pflag"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/discovery"
memory "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
// minikubectl is just a miniature in-process kubectl for us to use to avoid
// a binary dependency on the tool itself.
type minikubectl struct {
ConfigFlags *genericclioptions.ConfigFlags
ResourceBuilderFlags *genericclioptions.ResourceBuilderFlags
PrintFlags *genericclioptions.PrintFlags
IgnoreNotFound bool
restConfig *rest.Config
lock sync.Mutex
}
// newMinikubectl creates a new minikubectl, the empty state is not usable.
func newMinikubectl() *minikubectl {
outputFormat := ""
return &minikubectl{
ConfigFlags: genericclioptions.NewConfigFlags(true),
ResourceBuilderFlags: genericclioptions.NewResourceBuilderFlags().
WithLabelSelector("").
WithAll(true).
WithLatest(),
PrintFlags: &genericclioptions.PrintFlags{
JSONYamlPrintFlags: genericclioptions.NewJSONYamlPrintFlags(),
OutputFormat: &outputFormat,
},
}
}
// AddFlags configures the supplied flag set with the recognized flags.
func (k *minikubectl) AddFlags(flags *pflag.FlagSet) {
k.ConfigFlags.AddFlags(flags)
k.ResourceBuilderFlags.AddFlags(flags)
// PrintFlags somehow is tied to Cobra...
flags.StringVarP(k.PrintFlags.OutputFormat, "output", "o", *k.PrintFlags.OutputFormat, "")
// Don't bother with usage strings here, we aren't showing help to anyone
flags.BoolVar(&k.IgnoreNotFound, "ignore-not-found", k.IgnoreNotFound, "")
}
// Complete validates we can execute against the supplied arguments.
func (k *minikubectl) Complete(args []string) error {
if len(args) == 0 || args[0] != "get" {
return fmt.Errorf("minikubectl only supports get")
}
return nil
}
// Run executes the supplied arguments and returns the output as bytes.
func (k *minikubectl) Run(args []string) ([]byte, error) {
v := k.ResourceBuilderFlags.ToBuilder(k, args[1:]).Do()
// Create a printer to dump the objects
printer, err := k.PrintFlags.ToPrinter()
if err != nil {
return nil, err
}
// Use the printer to render everything into a byte buffer
var b bytes.Buffer
err = v.Visit(func(info *resource.Info, err error) error {
if err != nil {
if k.IgnoreNotFound && apierrors.IsNotFound(err) {
return nil
}
return err
}
return printer.PrintObj(info.Object, &b)
})
if err != nil {
return nil, err
}
return b.Bytes(), nil
}
// ToRawKubeConfigLoader just defers to the configuration flags.
func (k *minikubectl) ToRawKubeConfigLoader() clientcmd.ClientConfig {
return &namespaceOverrideClientConfig{
Delegate: k.ConfigFlags.ToRawKubeConfigLoader(),
NamespaceOverride: k.ConfigFlags.Namespace,
}
}
// ToRESTConfig lazily loads a REST configuration.
func (k *minikubectl) ToRESTConfig() (*rest.Config, error) {
k.lock.Lock()
defer k.lock.Unlock()
var err error
if k.restConfig != nil {
k.restConfig, err = k.ToRawKubeConfigLoader().ClientConfig()
}
return k.restConfig, err
}
// ToDiscoveryClient returns an in-memory cached discovery instance instead of an on-disk cached instance.
func (k *minikubectl) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
config, err := k.ToRESTConfig()
if err != nil {
return nil, err
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err
}
return memory.NewMemCacheClient(discoveryClient), nil
}
// ToRESTMapper does the exact same thing as the ConfigFlag implementation, just with a different discovery client.
func (k *minikubectl) ToRESTMapper() (meta.RESTMapper, error) {
discoveryClient, err := k.ToDiscoveryClient()
if err != nil {
return nil, err
}
mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
expander := restmapper.NewShortcutExpander(mapper, discoveryClient)
return expander, nil
}
type namespaceOverrideClientConfig struct {
Delegate clientcmd.ClientConfig
NamespaceOverride *string
}
func (c *namespaceOverrideClientConfig) Namespace() (string, bool, error) {
if c.NamespaceOverride != nil && *c.NamespaceOverride != "" {
return *c.NamespaceOverride, true, nil
}
return c.Delegate.Namespace()
}
// NOTE: Because the interface ClientConfig has a function ClientConfig we cannot simply embed ClientConfig
func (c *namespaceOverrideClientConfig) RawConfig() (clientcmdapi.Config, error) {
return c.Delegate.RawConfig()
}
func (c *namespaceOverrideClientConfig) ConfigAccess() clientcmd.ConfigAccess {
return c.Delegate.ConfigAccess()
}
func (c *namespaceOverrideClientConfig) ClientConfig() (*restclient.Config, error) {
return c.Delegate.ClientConfig()
}