Skip to content

Instantly share code, notes, and snippets.

@elig-salt
Created January 30, 2022 13:15
Show Gist options
  • Save elig-salt/fb63120ed3aa766e1d9053b6ae867517 to your computer and use it in GitHub Desktop.
Save elig-salt/fb63120ed3aa766e1d9053b6ae867517 to your computer and use it in GitHub Desktop.
Configure-telepresence
package cmd
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)
var current bool
var namespace string
var clusterName string
// configDebugCmd represents the configDebug command
var configDebugCmd = &cobra.Command{
Use: "config-debug",
Short: "Configure a local environment to work against telepresence",
Run: func(cmd *cobra.Command, args []string) {
if err := configDebug(); err != nil {
log.Fatal(err)
}
},
}
func init() {
configDebugCmd.Flags().BoolVar(&current, "current", false, "Use the currently selected cluster and namespace")
configDebugCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "the namespace to set")
configDebugCmd.Flags().StringVarP(&clusterName, "cluster", "c", "", "The cluster name to modify")
rootCmd.AddCommand(configDebugCmd)
}
func configDebug() error {
if clusterName == "" {
return errors.New("Please specify a cluster name")
}
if namespace == "" {
return errors.New("Please specify a namespace")
}
if namespace == "prod" {
return errors.New("Cannot use 'prod' namespace")
}
fmt.Printf("Pointing Telepresence on cluster \"%v\" to work against namespace \"%v\"\n", clusterName, namespace)
home, exists := os.LookupEnv("HOME")
if !exists {
home = "/root"
}
configPath := filepath.Join(home, ".kube", "config")
m := make(map[interface{}]interface{})
// Read the yaml from kubeconfig into t
if err := readConfig(m, configPath); err != nil {
return fmt.Errorf("Could not read config: %v", err)
}
if err := modifyKubeConfig(m, clusterName, namespace); err != nil {
return err
}
if err := writeConfig(m, configPath); err != nil {
return fmt.Errorf("Could not write config: %v", err)
}
fmt.Printf("Config saved to: \"%v\"\n", configPath)
return nil
}
func modifyKubeConfig(m map[interface{}]interface{}, clusterName, namespace string) error {
clustersFound := []string{}
clusters, ok := m["clusters"]
if !ok {
return fmt.Errorf("Corrupted kubeconfig file: Missing \"clusters\"")
} else {
clustersSlice, err := parseSlice(clusters)
if err != nil {
return fmt.Errorf("%v: clusters", err)
}
for _, currCluster := range clustersSlice {
clusterMap, err := parseMap(currCluster)
if err != nil {
return fmt.Errorf("%v: clusters", err)
}
clusterMapName, ok := clusterMap["name"]
if !ok {
return fmt.Errorf("Corrupted configuration: Missing Name in cluster")
}
currClusterName, ok := clusterMapName.(string)
if !ok {
return fmt.Errorf("Cluster name missing")
} else {
clustersFound = append(clustersFound, currClusterName)
if strings.HasSuffix(currClusterName, clusterName) {
clusterData, exists := clusterMap["cluster"]
if !exists {
return fmt.Errorf("Cluser config is corrupted: \"%v\"", currClusterName)
}
if clusterData := clusterData.(map[string]interface{}); ok {
setTelepresenceNamespaceToCluster(clusterData, namespace)
return nil
} else {
return fmt.Errorf("Cluser config is corrupted: \"%v\"", currClusterName)
}
}
}
}
return fmt.Errorf("Could not find requested cluster: %v\n\nClusters found:\n%v", clusterName, strings.Join(clustersFound, "\n"))
}
}
func readConfig(m map[interface{}]interface{}, configPath string) error {
yamlFile, err := ioutil.ReadFile(configPath)
if err != nil {
return fmt.Errorf("Error reading file: %v", err)
}
err = yaml.Unmarshal(yamlFile, &m)
if err != nil {
return fmt.Errorf("Error unmarshalling yaml: %v", err)
}
return nil
}
func writeConfig(config map[interface{}]interface{}, newConfigPath string) error {
var b bytes.Buffer
yamlEncoder := yaml.NewEncoder(&b)
yamlEncoder.SetIndent(2)
err := yamlEncoder.Encode(&config)
if err != nil {
return err
}
ioutil.WriteFile(newConfigPath, b.Bytes(), 600)
return nil
}
func setTelepresenceNamespaceToCluster(m map[string]interface{}, namespace string) {
m["extensions"] = []map[string]interface{}{
{
"extension": map[string]interface{}{
"manager": map[string]interface{}{
"namespace": namespace,
},
},
"name": "telepresence.io",
},
}
}
func parseMap(val interface{}) (map[string]interface{}, error) {
if mapVals, ok := val.(map[string]interface{}); ok {
return mapVals, nil
}
return nil, errors.New("Could not parse map")
}
func parseSlice(val interface{}) ([]interface{}, error) {
if slice, ok := val.([]interface{}); ok {
return slice, nil
}
return nil, errors.New("Could not parse slice")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment