158 lines
4.3 KiB
Go
158 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"katenary/compose"
|
|
"katenary/generator"
|
|
"katenary/helm"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var ComposeFile = "docker-compose.yaml"
|
|
var AppName = "MyApp"
|
|
var AppVersion = "0.0.1"
|
|
var Version = "master"
|
|
var ChartsDir = "chart"
|
|
|
|
func main() {
|
|
|
|
flag.StringVar(&ChartsDir, "chart-dir", ChartsDir, "set the chart directory")
|
|
flag.StringVar(&ComposeFile, "compose", ComposeFile, "set the compose file to parse")
|
|
flag.StringVar(&AppName, "appname", AppName, "sive the helm chart app name")
|
|
flag.StringVar(&AppVersion, "appversion", AppVersion, "set the chart appVersion")
|
|
version := flag.Bool("version", false, "Show version and exit")
|
|
force := flag.Bool("force", false, "force the removal of the chart-dir")
|
|
flag.Parse()
|
|
|
|
if *version {
|
|
fmt.Println(Version)
|
|
os.Exit(0)
|
|
}
|
|
|
|
dirname := filepath.Join(ChartsDir, AppName)
|
|
|
|
if _, err := os.Stat(dirname); err == nil && !*force {
|
|
response := ""
|
|
for response != "y" && response != "n" {
|
|
response = "n"
|
|
fmt.Printf("The %s directory already exists, it will be \x1b[31;1mremoved\x1b[0m!\nDo you really want to continue ? [y/N]: ", dirname)
|
|
fmt.Scanf("%s", &response)
|
|
response = strings.ToLower(response)
|
|
}
|
|
if response == "n" {
|
|
fmt.Println("Cancelled")
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
|
|
os.RemoveAll(dirname)
|
|
templatesDir := filepath.Join(dirname, "templates")
|
|
os.MkdirAll(templatesDir, 0755)
|
|
|
|
helm.Version = Version
|
|
p := compose.NewParser(ComposeFile)
|
|
p.Parse(AppName)
|
|
wait := sync.WaitGroup{}
|
|
|
|
files := make(map[string][]interface{})
|
|
|
|
for name, s := range p.Data.Services {
|
|
wait.Add(1)
|
|
// it's mandatory to build in goroutines because some dependencies can
|
|
// wait for a port number discovery.
|
|
// So the entire services are built in parallel.
|
|
go func(name string, s compose.Service) {
|
|
o := generator.CreateReplicaObject(name, s)
|
|
files[name] = o
|
|
wait.Done()
|
|
}(name, s)
|
|
}
|
|
wait.Wait()
|
|
|
|
// to generate notes, we need to keep an Ingresses list
|
|
ingresses := make(map[string]*helm.Ingress)
|
|
|
|
for n, f := range files {
|
|
for _, c := range f {
|
|
kind := c.(helm.Kinded).Get()
|
|
kind = strings.ToLower(kind)
|
|
fname := filepath.Join(templatesDir, n+"."+kind+".yaml")
|
|
fp, _ := os.Create(fname)
|
|
switch c := c.(type) {
|
|
case *helm.Storage:
|
|
volname := c.K8sBase.Metadata.Labels[helm.K+"/pvc-name"]
|
|
fp.WriteString("{{ if .Values." + n + ".persistence." + volname + ".enabled }}\n")
|
|
enc := yaml.NewEncoder(fp)
|
|
enc.SetIndent(2)
|
|
enc.Encode(c)
|
|
fp.WriteString("{{- end -}}")
|
|
case *helm.Deployment:
|
|
buffer := bytes.NewBuffer(nil)
|
|
enc := yaml.NewEncoder(buffer)
|
|
enc.SetIndent(2)
|
|
enc.Encode(c)
|
|
_content := string(buffer.Bytes())
|
|
content := strings.Split(string(_content), "\n")
|
|
dataname := ""
|
|
component := c.Spec.Selector["matchLabels"].(map[string]string)[helm.K+"/component"]
|
|
for _, line := range content {
|
|
if strings.Contains(line, "name:") {
|
|
dataname = strings.Split(line, ":")[1]
|
|
dataname = strings.TrimSpace(dataname)
|
|
} else if strings.Contains(line, "persistentVolumeClaim") {
|
|
line = " {{- if .Values." + component + ".persistence." + dataname + ".enabled }}\n" + line
|
|
} else if strings.Contains(line, "claimName") {
|
|
line += "\n {{ else }}"
|
|
line += "\n emptyDir: {}"
|
|
line += "\n {{- end }}"
|
|
}
|
|
fp.WriteString(line + "\n")
|
|
}
|
|
case *helm.Ingress:
|
|
ingresses[n] = c // keep it to generate notes
|
|
enc := yaml.NewEncoder(fp)
|
|
enc.SetIndent(2)
|
|
fp.WriteString("{{- if .Values." + n + ".ingress.enabled -}}\n")
|
|
enc.Encode(c)
|
|
fp.WriteString("{{- end -}}")
|
|
|
|
default:
|
|
enc := yaml.NewEncoder(fp)
|
|
enc.SetIndent(2)
|
|
enc.Encode(c)
|
|
}
|
|
fp.Close()
|
|
}
|
|
}
|
|
|
|
fp, _ := os.Create(filepath.Join(dirname, "values.yaml"))
|
|
enc := yaml.NewEncoder(fp)
|
|
enc.SetIndent(2)
|
|
enc.Encode(generator.Values)
|
|
fp.Close()
|
|
|
|
fp, _ = os.Create(filepath.Join(dirname, "Chart.yaml"))
|
|
enc = yaml.NewEncoder(fp)
|
|
enc.SetIndent(2)
|
|
enc.Encode(map[string]interface{}{
|
|
"apiVersion": "v2",
|
|
"name": AppName,
|
|
"description": "A helm chart for " + AppName,
|
|
"type": "application",
|
|
"version": "0.1.0",
|
|
"appVersion": AppVersion,
|
|
})
|
|
fp.Close()
|
|
|
|
fp, _ = os.Create(filepath.Join(templatesDir, "NOTES.txt"))
|
|
fp.WriteString(helm.GenNotes(ingresses))
|
|
fp.Close()
|
|
}
|