sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/cmd/cm2kc/main.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 "sort" 24 25 flag "github.com/spf13/pflag" 26 clientcmdapi "k8s.io/client-go/tools/clientcmd/api/v1" 27 "sigs.k8s.io/yaml" 28 29 "sigs.k8s.io/prow/pkg/kube" 30 ) 31 32 const ( 33 // defaultInput is the default input source. 34 defaultInput = "/dev/stdin" 35 // defaultOutput is the default output source. 36 defaultOutput = "/dev/stdout" 37 ) 38 39 // Cluster represents the information necessary to talk to a Kubernetes master endpoint. 40 type Cluster struct { 41 // The IP address of the cluster's master endpoint. 42 Endpoint string `json:"endpoint"` 43 // Base64-encoded public cert used by clients to authenticate to the cluster endpoint. 44 ClientCertificate []byte `json:"clientCertificate"` 45 // Base64-encoded private key used by clients.. 46 ClientKey []byte `json:"clientKey"` 47 // Base64-encoded public certificate that is the root of trust for the cluster. 48 ClusterCACertificate []byte `json:"clusterCaCertificate"` 49 } 50 51 // options are the available command-line flags. 52 type options struct { 53 input string 54 output string 55 } 56 57 // parseFlags parses the command-line flags. 58 func (o *options) parseFlags() { 59 flag.StringVarP(&o.input, "input", "i", defaultInput, "Input cluster map file.") 60 flag.StringVarP(&o.output, "output", "o", defaultOutput, "Output kubeconfig file.") 61 62 flag.Parse() 63 } 64 65 // printErrAndExit prints an error message to stderr and exits with a status code. 66 func printErrAndExit(err error, code int) { 67 _, _ = fmt.Fprintln(os.Stderr, err.Error()) 68 os.Exit(code) 69 } 70 71 // unmarshalClusterMap reads a map[string]Cluster in yaml bytes. 72 func unmarshalClusterMap(data []byte) (map[string]Cluster, error) { 73 var raw map[string]Cluster 74 if err := yaml.Unmarshal(data, &raw); err != nil { 75 // If we failed to unmarshal the multicluster format try the single Cluster format. 76 var singleConfig Cluster 77 if err := yaml.Unmarshal(data, &singleConfig); err != nil { 78 return nil, err 79 } 80 raw = map[string]Cluster{kube.DefaultClusterAlias: singleConfig} 81 } 82 return raw, nil 83 } 84 85 // createKubeConfigFromClusterMap creates a standard kube config from a cluster map. 86 func createKubeConfigFromClusterMap(cm map[string]Cluster) ([]byte, error) { 87 config := clientcmdapi.Config{ 88 APIVersion: "v1", 89 Kind: "Config", 90 Clusters: []clientcmdapi.NamedCluster{}, 91 AuthInfos: []clientcmdapi.NamedAuthInfo{}, 92 Contexts: []clientcmdapi.NamedContext{}, 93 CurrentContext: kube.DefaultClusterAlias, 94 } 95 96 names := make([]string, 0, len(cm)) 97 98 for k := range cm { 99 names = append(names, k) 100 } 101 102 sort.Strings(names) 103 104 for _, name := range names { 105 config.Clusters = append(config.Clusters, clientcmdapi.NamedCluster{ 106 Name: name, 107 Cluster: clientcmdapi.Cluster{ 108 Server: cm[name].Endpoint, 109 CertificateAuthorityData: cm[name].ClusterCACertificate, 110 }, 111 }) 112 config.AuthInfos = append(config.AuthInfos, clientcmdapi.NamedAuthInfo{ 113 Name: name, 114 AuthInfo: clientcmdapi.AuthInfo{ 115 ClientCertificateData: cm[name].ClientCertificate, 116 ClientKeyData: cm[name].ClientKey, 117 }, 118 }) 119 config.Contexts = append(config.Contexts, clientcmdapi.NamedContext{ 120 Name: name, 121 Context: clientcmdapi.Context{ 122 Cluster: name, 123 AuthInfo: name, 124 }, 125 }) 126 } 127 128 return yaml.Marshal(config) 129 } 130 131 // main entry point. 132 func main() { 133 var o options 134 135 o.parseFlags() 136 137 in, err := os.ReadFile(o.input) 138 if err != nil { 139 printErrAndExit(err, 1) 140 } 141 142 cm, err := unmarshalClusterMap(in) 143 if err != nil { 144 printErrAndExit(err, 1) 145 } 146 147 kc, err := createKubeConfigFromClusterMap(cm) 148 if err != nil { 149 printErrAndExit(err, 1) 150 } 151 152 dir := filepath.Dir(o.output) 153 if err = os.MkdirAll(dir, os.ModePerm); err != nil { 154 printErrAndExit(err, 1) 155 } 156 157 if err = os.WriteFile(o.output, kc, 0644); err != nil { 158 printErrAndExit(err, 1) 159 } 160 }