github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/install/kubeconfig.go (about)

     1  package install
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"html/template"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/apprenda/kismatic/pkg/util"
    13  )
    14  
    15  const kubeconfigFilename = "kubeconfig"
    16  const dashboardAdminKubeconfigFilename = "dashboard-admin-kubeconfig"
    17  
    18  // ConfigOptions sds
    19  type ConfigOptions struct {
    20  	CA      string
    21  	Server  string
    22  	Cluster string
    23  	User    string
    24  	Context string
    25  	Cert    string
    26  	Key     string
    27  	Token   string
    28  }
    29  
    30  var kubeconfigTemplate = `apiVersion: v1
    31  clusters:
    32  - cluster:
    33      certificate-authority-data: {{.CA}}
    34      server: {{.Server}}
    35    name: {{.Cluster}}
    36  contexts:
    37  - context:
    38      cluster: {{.Cluster}}
    39      user: {{.User}}
    40    name: {{.Context}}
    41  current-context: {{.Context}}
    42  kind: Config
    43  preferences: {}
    44  users:
    45  - name: {{.User}}
    46    user:
    47      client-certificate-data: {{.Cert}}
    48      client-key-data: {{.Key}}
    49      token: {{.Token}}
    50  `
    51  
    52  // GenerateKubeconfig generate a kubeconfig file for a specific user
    53  func GenerateKubeconfig(p *Plan, generatedAssetsDir string) error {
    54  	user := "admin"
    55  	server := "https://" + p.Master.LoadBalancedFQDN + ":6443"
    56  	cluster := p.Cluster.Name
    57  	context := p.Cluster.Name + "-" + user
    58  
    59  	certsDir := filepath.Join(generatedAssetsDir, "keys")
    60  
    61  	// Base64 encoded ca
    62  	caEncoded, err := util.Base64String(filepath.Join(certsDir, "ca.pem"))
    63  	if err != nil {
    64  		return fmt.Errorf("error reading ca file for kubeconfig: %v", err)
    65  	}
    66  	// Base64 encoded cert
    67  	certEncoded, err := util.Base64String(filepath.Join(certsDir, user+".pem"))
    68  	if err != nil {
    69  		return fmt.Errorf("error reading certificate file for kubeconfig: %v", err)
    70  	}
    71  	// Base64 encoded key
    72  	keyEncoded, err := util.Base64String(filepath.Join(certsDir, user+"-key.pem"))
    73  	if err != nil {
    74  		return fmt.Errorf("error reading certificate key file for kubeconfig: %v", err)
    75  	}
    76  
    77  	configOptions := ConfigOptions{caEncoded, server, cluster, user, context, certEncoded, keyEncoded, ""}
    78  
    79  	return writeTemplate(configOptions, filepath.Join(generatedAssetsDir, kubeconfigFilename))
    80  }
    81  
    82  func GenerateDashboardAdminKubeconfig(base64token string, p *Plan, generatedAssetsDir string) error {
    83  	user := "admin"
    84  	server := "https://" + p.Master.LoadBalancedFQDN + ":6443"
    85  	cluster := p.Cluster.Name
    86  	context := p.Cluster.Name + "-" + "dashboard-admin"
    87  
    88  	certsDir := filepath.Join(generatedAssetsDir, "keys")
    89  
    90  	// Base64 encoded ca
    91  	caEncoded, err := util.Base64String(filepath.Join(certsDir, "ca.pem"))
    92  	if err != nil {
    93  		return fmt.Errorf("error reading ca file for kubeconfig: %v", err)
    94  	}
    95  
    96  	token, err := base64.StdEncoding.DecodeString(base64token)
    97  	if err != nil {
    98  		return fmt.Errorf("error decoding token: %v", err)
    99  	}
   100  	configOptions := ConfigOptions{caEncoded, server, cluster, user, context, "", "", string(token)}
   101  
   102  	return writeTemplate(configOptions, filepath.Join(generatedAssetsDir, dashboardAdminKubeconfigFilename))
   103  }
   104  
   105  func writeTemplate(conf ConfigOptions, file string) error {
   106  	// Process template file
   107  	tmpl, err := template.New("kubeconfig").Parse(kubeconfigTemplate)
   108  	if err != nil {
   109  		return fmt.Errorf("error reading config template: %v", err)
   110  	}
   111  
   112  	var kubeconfig bytes.Buffer
   113  	err = tmpl.Execute(&kubeconfig, conf)
   114  	if err != nil {
   115  		return fmt.Errorf("error processing config template: %v", err)
   116  	}
   117  	// Write config file
   118  	err = ioutil.WriteFile(file, kubeconfig.Bytes(), 0644)
   119  	if err != nil {
   120  		return fmt.Errorf("error writing kubeconfig file: %v", err)
   121  	}
   122  	return nil
   123  }
   124  
   125  // RegenerateKubeconfig backs up the old kubeconfig file if it exists. Returns
   126  // true if the new kubeconfig file is different than the previous one.
   127  // Otherwise returns false.
   128  func RegenerateKubeconfig(p *Plan, generatedAssetsDir string) (bool, error) {
   129  	kubeconfigFile := filepath.Join(generatedAssetsDir, kubeconfigFilename)
   130  	kubeconfigBackup := filepath.Join(generatedAssetsDir, kubeconfigFilename) + ".bak"
   131  
   132  	err := os.Rename(kubeconfigFile, kubeconfigBackup)
   133  	if os.IsNotExist(err) {
   134  		// Nothing else to do as the old kubeconfig does not exist
   135  		return false, GenerateKubeconfig(p, generatedAssetsDir)
   136  	}
   137  	if err != nil {
   138  		return false, fmt.Errorf("error backing up existing kubeconfig file: %v", err)
   139  	}
   140  
   141  	if err := GenerateKubeconfig(p, generatedAssetsDir); err != nil {
   142  		return false, err
   143  	}
   144  
   145  	// Check if the new kubeconfig is different than the previous one
   146  	old, err := ioutil.ReadFile(kubeconfigBackup)
   147  	if err != nil {
   148  		return false, fmt.Errorf("error reading file %q: %v", kubeconfigBackup, err)
   149  	}
   150  	new, err := ioutil.ReadFile(kubeconfigFile)
   151  	if err != nil {
   152  		return false, fmt.Errorf("error reading file %q: %v", kubeconfigFile, err)
   153  	}
   154  	if bytes.Equal(old, new) {
   155  		os.Remove(kubeconfigBackup)
   156  		return false, nil
   157  	}
   158  
   159  	return true, nil
   160  }