github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/cli/client/getter.go (about) 1 /* 2 Adapted from 3 https://github.com/kubernetes/cli-runtime/tree/master/pkg/genericclioptions 4 */ 5 6 /* 7 Copyright 2014 The Kubernetes Authors. 8 9 Licensed under the Apache License, Version 2.0 (the "License"); 10 you may not use this file except in compliance with the License. 11 You may obtain a copy of the License at 12 13 http://www.apache.org/licenses/LICENSE-2.0 14 15 Unless required by applicable law or agreed to in writing, software 16 distributed under the License is distributed on an "AS IS" BASIS, 17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 See the License for the specific language governing permissions and 19 limitations under the License. 20 */ 21 22 package client 23 24 import ( 25 "path/filepath" 26 "regexp" 27 "strings" 28 "time" 29 30 "k8s.io/apimachinery/pkg/api/meta" 31 "k8s.io/cli-runtime/pkg/genericclioptions" 32 "k8s.io/client-go/discovery" 33 diskcached "k8s.io/client-go/discovery/cached/disk" 34 "k8s.io/client-go/rest" 35 "k8s.io/client-go/restmapper" 36 "k8s.io/client-go/tools/clientcmd" 37 38 "github.com/tilt-dev/wmclient/pkg/dirs" 39 ) 40 41 // Composes the set of values necessary 42 // for obtaining a REST client config 43 type Getter struct { 44 dir *dirs.TiltDevDir 45 config TiltClientConfig 46 } 47 48 func NewGetter(dir *dirs.TiltDevDir, config TiltClientConfig) *Getter { 49 return &Getter{dir: dir, config: config} 50 } 51 52 var _ genericclioptions.RESTClientGetter = &Getter{} 53 54 // ToRESTConfig implements RESTClientGetter. 55 // Returns a REST client configuration based on a provided path 56 // to a .kubeconfig file, loading rules, and config flag overrides. 57 // Expects the AddFlags method to have been called. 58 func (f *Getter) ToRESTConfig() (*rest.Config, error) { 59 return f.ToRawKubeConfigLoader().ClientConfig() 60 } 61 62 // ToRawKubeConfigLoader binds config flag values to config overrides 63 // Returns an interactive clientConfig if the password flag is enabled, 64 // or a non-interactive clientConfig otherwise. 65 func (f *Getter) ToRawKubeConfigLoader() clientcmd.ClientConfig { 66 return clientcmd.ClientConfig(f.config) 67 } 68 69 // ToDiscoveryClient implements RESTClientGetter. 70 // Expects the AddFlags method to have been called. 71 // Returns a CachedDiscoveryInterface using a computed RESTConfig. 72 func (f *Getter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { 73 config, err := f.ToRESTConfig() 74 if err != nil { 75 return nil, err 76 } 77 78 // The more groups you have, the more discovery requests you need to make. 79 // given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests 80 // double it just so we don't end up here again for a while. This config is only used for discovery. 81 config.Burst = 100 82 83 cacheDir := filepath.Join(f.dir.Root(), "cache") 84 httpCacheDir := filepath.Join(cacheDir, "http") 85 discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(cacheDir, "discovery"), config.Host) 86 87 return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, 10*time.Minute) 88 } 89 90 func (f *Getter) ToRESTMapper() (meta.RESTMapper, error) { 91 discoveryClient, err := f.ToDiscoveryClient() 92 if err != nil { 93 return nil, err 94 } 95 96 mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) 97 98 warningHandler := func(warning string) { 99 // no-op for now. historically we've found that these warnings 100 // are targeted at people writing kubernetes controllers, and won't 101 // make sense to tilt users. 102 } 103 expander := restmapper.NewShortcutExpander(mapper, discoveryClient, warningHandler) 104 return expander, nil 105 } 106 107 // overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive 108 var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`) 109 110 // computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name. 111 func computeDiscoverCacheDir(parentDir, host string) string { 112 // strip the optional scheme from host if its there: 113 schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1) 114 // now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived 115 safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_") 116 return filepath.Join(parentDir, safeHost) 117 }