| giolekva | a4a153b | 2020-05-12 11:49:53 +0400 | [diff] [blame^] | 1 | package appmanager |
| 2 | |
| 3 | import ( |
| 4 | "errors" |
| 5 | "fmt" |
| 6 | "io/ioutil" |
| 7 | "os" |
| 8 | "os/exec" |
| 9 | "path" |
| 10 | "path/filepath" |
| 11 | "strings" |
| 12 | |
| 13 | "github.com/golang/glog" |
| 14 | "gopkg.in/yaml.v2" |
| 15 | ) |
| 16 | |
| 17 | type Chart struct { |
| 18 | Name string `yaml:"name"` |
| 19 | } |
| 20 | |
| 21 | type HelmChart struct { |
| 22 | Chart |
| 23 | chartDir string |
| 24 | Schema *Schema |
| 25 | Yamls []string |
| 26 | } |
| 27 | |
| 28 | func HelmChartFromDir(chartDir string) (*HelmChart, error) { |
| 29 | var chart HelmChart |
| 30 | chart.chartDir = chartDir |
| 31 | c, err := ReadChart(path.Join(chartDir, "Chart.yaml")) |
| 32 | if err != nil { |
| 33 | return nil, err |
| 34 | } |
| 35 | chart.Chart = *c |
| 36 | schema, err := ReadSchema(path.Join(chartDir, "Schema.yaml")) |
| 37 | if err != nil && os.IsNotExist(err) { |
| 38 | return nil, err |
| 39 | } |
| 40 | chart.Schema = schema |
| 41 | return &chart, nil |
| 42 | } |
| 43 | |
| 44 | func HelmChartFromTar(chartTar string) (*HelmChart, error) { |
| 45 | if !strings.HasSuffix(chartTar, ".tar.gz") { |
| 46 | return nil, errors.New("Expected .tar.gz file") |
| 47 | } |
| 48 | dir := filepath.Dir(chartTar) |
| 49 | archive := filepath.Base(chartTar) |
| 50 | extractDir := strings.TrimSuffix(archive, ".tar.gz") |
| 51 | cmd := exec.Command(fmt.Sprintf("cd %s && rm -rf %s && tar -ztvf %s -C %s", dir, extractDir, archive, extractDir)) |
| 52 | if err := cmd.Run(); err != nil { |
| 53 | return nil, err |
| 54 | } |
| 55 | return HelmChartFromDir(dir + "/" + extractDir) |
| 56 | } |
| 57 | |
| 58 | func (h *HelmChart) Install( |
| 59 | helmBin string, |
| 60 | values map[string]string) error { |
| 61 | namespace := fmt.Sprintf("app-%s", h.Chart.Name) |
| 62 | cmd := generateHelmInstallCmd(helmBin, h.chartDir, namespace, values) |
| 63 | glog.Info(cmd.String()) |
| 64 | var stdout strings.Builder |
| 65 | var stderr strings.Builder |
| 66 | cmd.Stdout = &stdout |
| 67 | cmd.Stderr = &stderr |
| 68 | err := cmd.Run() |
| 69 | if err != nil { |
| 70 | return errors.New(stderr.String()) |
| 71 | } |
| 72 | glog.Info(stdout.String()) |
| 73 | return nil |
| 74 | } |
| 75 | |
| 76 | func generateHelmInstallCmd( |
| 77 | helmBin string, |
| 78 | archive string, |
| 79 | namespace string, |
| 80 | values map[string]string) *exec.Cmd { |
| 81 | cmd := exec.Command(helmBin) |
| 82 | cmd.Args = append(cmd.Args, "install") |
| 83 | cmd.Args = append(cmd.Args, fmt.Sprintf("--namespace=%s", namespace)) |
| 84 | cmd.Args = append(cmd.Args, "--generate-name") |
| 85 | cmd.Args = append(cmd.Args, fmt.Sprintf("%s", archive)) |
| 86 | // TODO(giolekva): validate values |
| 87 | for key, value := range values { |
| 88 | cmd.Args = append(cmd.Args, fmt.Sprintf("--set=%s=%s", key, value)) |
| 89 | } |
| 90 | return cmd |
| 91 | } |
| 92 | |
| 93 | func ChartFromYaml(str string) (*Chart, error) { |
| 94 | var s Chart |
| 95 | err := yaml.Unmarshal([]byte(str), &s) |
| 96 | if err != nil { |
| 97 | return nil, err |
| 98 | } |
| 99 | return &s, nil |
| 100 | } |
| 101 | |
| 102 | func ReadChart(chartFile string) (*Chart, error) { |
| 103 | f, err := os.Open(chartFile) |
| 104 | if err != nil { |
| 105 | return nil, err |
| 106 | } |
| 107 | defer f.Close() |
| 108 | b, err := ioutil.ReadAll(f) |
| 109 | if err != nil { |
| 110 | return nil, err |
| 111 | } |
| 112 | return ChartFromYaml(string(b)) |
| 113 | } |