github.imxd.top/operator-framework/operator-sdk@v0.8.2/pkg/ansible/proxy/kubeconfig/kubeconfig.go (about) 1 // Copyright 2018 The Operator-SDK 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 kubeconfig 16 17 import ( 18 "bytes" 19 "encoding/base64" 20 "encoding/json" 21 "html/template" 22 "io/ioutil" 23 "net/url" 24 "os" 25 26 "github.com/operator-framework/operator-sdk/internal/util/fileutil" 27 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" 30 ) 31 32 var log = logf.Log.WithName("kubeconfig") 33 34 // kubectl, as of 1.10.5, only does basic auth if the username is present in 35 // the URL. The python client used by ansible, as of 6.0.0, only does basic 36 // auth if the username and password are provided under the "user" key within 37 // "users". 38 const kubeConfigTemplate = `--- 39 apiVersion: v1 40 kind: Config 41 clusters: 42 - cluster: 43 insecure-skip-tls-verify: true 44 server: {{.ProxyURL}} 45 name: proxy-server 46 contexts: 47 - context: 48 cluster: proxy-server 49 user: admin/proxy-server 50 name: {{.Namespace}}/proxy-server 51 current-context: {{.Namespace}}/proxy-server 52 preferences: {} 53 users: 54 - name: admin/proxy-server 55 user: 56 username: {{.Username}} 57 password: unused 58 ` 59 60 // values holds the data used to render the template 61 type values struct { 62 Username string 63 ProxyURL string 64 Namespace string 65 } 66 67 type NamespacedOwnerReference struct { 68 metav1.OwnerReference 69 Namespace string 70 } 71 72 // Create renders a kubeconfig template and writes it to disk 73 func Create(ownerRef metav1.OwnerReference, proxyURL string, namespace string) (*os.File, error) { 74 nsOwnerRef := NamespacedOwnerReference{OwnerReference: ownerRef, Namespace: namespace} 75 parsedURL, err := url.Parse(proxyURL) 76 if err != nil { 77 return nil, err 78 } 79 ownerRefJSON, err := json.Marshal(nsOwnerRef) 80 if err != nil { 81 return nil, err 82 } 83 username := base64.URLEncoding.EncodeToString([]byte(ownerRefJSON)) 84 parsedURL.User = url.User(username) 85 v := values{ 86 Username: username, 87 ProxyURL: parsedURL.String(), 88 Namespace: namespace, 89 } 90 91 var parsed bytes.Buffer 92 93 t := template.Must(template.New("kubeconfig").Parse(kubeConfigTemplate)) 94 if err := t.Execute(&parsed, v); err != nil { 95 return nil, err 96 } 97 98 file, err := ioutil.TempFile("", "kubeconfig") 99 if err != nil { 100 return nil, err 101 } 102 // multiple calls to close file will not hurt anything, 103 // but we don't want to lose the error because we are 104 // writing to the file, so we will call close twice. 105 defer func() { 106 if err := file.Close(); err != nil && !fileutil.IsClosedError(err) { 107 log.Error(err, "Failed to close generated kubeconfig file") 108 } 109 }() 110 111 if _, err := file.WriteString(parsed.String()); err != nil { 112 return nil, err 113 } 114 if err := file.Close(); err != nil { 115 return nil, err 116 } 117 return file, nil 118 }