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  }