helm-import/cmd/main.go

253 lines
8.6 KiB
Go

package main
import (
"flag"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"git.martyn.berlin/martyn/helm-import/internal/exporters"
//
// Uncomment to load all auth plugins
// "k8s.io/client-go/plugin/pkg/client/auth"
//
// Or uncomment to load specific auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
// _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
// _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
// _ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
)
type objectFlags []string
func (i *objectFlags) String() string {
return strings.Join(*i, ", ")
}
func (i *objectFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
type jqCommands []string
func (i *jqCommands) String() string {
return strings.Join(*i, ", ")
}
func (i *jqCommands) Set(value string) error {
*i = append(*i, value)
return nil
}
var deployments objectFlags
var services objectFlags
var configmaps objectFlags
var secrets objectFlags
var ingresses objectFlags
var namespace string
var noBuiltinMods bool
var lessOpinions bool
var deploymentJqCommands jqCommands
var serviceJqCommands jqCommands
var ingressJqCommands jqCommands
var globalJqCommands jqCommands
var configmapJqCommands jqCommands
var secretJqCommands jqCommands
type chartDef struct {
APIVersion string `json: "apiVersion"`
Name string `json: "name"`
Description string `json: "description"`
Type string `json: "type"`
Version string `json: "version"`
AppVersion string `json: "appVersion"`
}
var chart chartDef
func main() {
chartYamlFile, err := ioutil.ReadFile("Chart.yaml")
if err != nil {
panic("Run this from the chart folder, where Chart.yaml is. Error: " + err.Error())
}
err = yaml.Unmarshal(chartYamlFile, &chart)
if err != nil {
panic("Could not read the chart yaml as expected. Error: " + err.Error())
}
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.StringVar(&namespace, "namespace", "default", "namespace to work in")
flag.Var(&deployments, "deployment", "deployment to import into the helm chart (can be specified multiple times)")
flag.Var(&services, "service", "service to import into the helm chart (can be specified multiple times)")
flag.Var(&configmaps, "configmap", "configmap to import into the helm chart (can be specified multiple times)")
flag.Var(&secrets, "secret", "secret to import into the helm chart (can be specified multiple times)")
flag.Var(&ingresses, "ingress", "ingress to import into the helm chart (can be specified multiple times)")
flag.BoolVar(&noBuiltinMods, "nobuiltinmods", false, "don't do the built-in modifications, only ones passed in by user")
flag.BoolVar(&lessOpinions, "lessopinions", false, "just import the objects into files, don't get opinionated")
flag.Var(&globalJqCommands, "globalJqCommands", "extra jq commands to apply to all k8s objects")
flag.Var(&deploymentJqCommands, "deploymentJqCommands", "extra jq commands to apply to deployments")
flag.Var(&serviceJqCommands, "serviceJqCommands", "extra jq commands to apply to services")
flag.Var(&configmapJqCommands, "configmapJqCommands", "extra jq commands to apply to configmaps")
flag.Var(&secretJqCommands, "secretJqCommands", "extra jq commands to apply to secrets")
flag.Var(&ingressJqCommands, "ingressJqCommands", "extra jq commands to apply to ingresses")
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
var y = ""
fileString := ""
for _, deployment := range deployments {
deploymentObject, err := clientset.AppsV1().Deployments(namespace).Get(deployment, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("Deployment %s in namespace %s not found\n", deployment, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting deployment %s in namespace %s: %v\n",
deployment, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found deployment %s in namespace %s\n", deployment, namespace)
y = exporters.Deployment(deploymentObject, append(deploymentJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
}
if y != "" {
err = ioutil.WriteFile("templates/imported-deployment.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, service := range services {
serviceObject, err := clientset.CoreV1().Services(namespace).Get(service, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("service %s in namespace %s not found\n", service, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting service %s in namespace %s: %v\n",
service, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found service %s in namespace %s\n", service, namespace)
y = exporters.Service(serviceObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
}
if y != "" {
err = ioutil.WriteFile("templates/imported-service.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, configmap := range configmaps {
configmapObject, err := clientset.CoreV1().ConfigMaps(namespace).Get(configmap, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("configmap %s in namespace %s not found\n", configmap, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting configmap %s in namespace %s: %v\n",
configmap, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found configmap %s in namespace %s\n", configmap, namespace)
y = exporters.Configmap(configmapObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-configmap.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, secret := range secrets {
secretObject, err := clientset.CoreV1().Secrets(namespace).Get(secret, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("secret %s in namespace %s not found\n", secret, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting secret %s in namespace %s: %v\n",
secret, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found secret %s in namespace %s\n", secret, namespace)
y = exporters.Secret(secretObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-secret.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
for _, ingress := range ingresses {
ingressObject, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Get(ingress, metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("ingress %s in namespace %s not found\n", ingress, namespace)
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting ingress %s in namespace %s: %v\n",
ingress, namespace, statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found ingress %s in namespace %s\n", ingress, namespace)
y = exporters.Ingress(ingressObject, append(serviceJqCommands, globalJqCommands...), noBuiltinMods, chart.Name, lessOpinions)
}
if fileString != "" {
fileString += "---\n"
}
fileString += y
}
if y != "" {
err = ioutil.WriteFile("templates/imported-ingress.yaml", []byte(fileString), 0644)
if err != nil {
panic(err.Error())
}
}
}