| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- package api
- import (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
- "github.com/porter-dev/porter/internal/forms"
- "github.com/porter-dev/porter/internal/helm"
- "github.com/porter-dev/porter/internal/models"
- "gopkg.in/yaml.v2"
- )
- // HandleDeployTemplate triggers a chart deployment from a template
- func (app *App) HandleDeployTemplate(w http.ResponseWriter, r *http.Request) {
- vals, err := url.ParseQuery(r.URL.RawQuery)
- if err != nil {
- app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
- return
- }
- form := &forms.InstallChartTemplateForm{
- ReleaseForm: &forms.ReleaseForm{
- Form: &helm.Form{
- Repo: app.repo,
- },
- },
- ChartTemplateForm: &forms.ChartTemplateForm{},
- }
- form.ReleaseForm.PopulateHelmOptionsFromQueryParams(
- vals,
- app.repo.Cluster,
- )
- if err := json.NewDecoder(r.Body).Decode(form); err != nil {
- app.handleErrorFormDecoding(err, ErrUserDecode, w)
- return
- }
- agent, err := app.getAgentFromReleaseForm(
- w,
- r,
- form.ReleaseForm,
- )
- if err != nil {
- return
- }
- baseURL := "https://porter-dev.github.io/chart-repo/"
- values, err := getDefaultValues(form.ChartTemplateForm.TemplateName, baseURL)
- if err != nil {
- return
- }
- // Set image URL
- if form.ChartTemplateForm.ImageURL != "" {
- (*values)["image"].(map[interface{}]interface{})["repository"] = form.ChartTemplateForm.ImageURL
- }
- // Loop through form params to override
- for k := range form.ChartTemplateForm.FormValues {
- switch v := interface{}(k).(type) {
- case string:
- splits := strings.Split(v, ".")
- // Validate that the field to override exists
- currentLoc := *values
- for s := range splits {
- key := splits[s]
- val := currentLoc[key]
- if val == nil {
- fmt.Printf("No such field: %v\n", key)
- } else if s == len(splits)-1 {
- newValue := form.ChartTemplateForm.FormValues[v]
- fmt.Printf("Overriding default %v with %v\n", val, newValue)
- currentLoc[key] = newValue
- } else {
- fmt.Println("Traversing...")
- currentLoc = val.(map[interface{}]interface{})
- }
- }
- default:
- fmt.Println("Non-string type")
- }
- }
- v, err := yaml.Marshal(values)
- if err != nil {
- return
- }
- var tgz string
- switch form.ChartTemplateForm.TemplateName {
- case "redis":
- tgz = "redis-0.0.1.tgz"
- }
- // Output values.yaml string
- _, err = agent.InstallChart(
- "./internal/local_templates/"+tgz,
- v,
- form.ChartTemplateForm.Name,
- form.ReleaseForm.Form.Namespace,
- )
- if err != nil {
- app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
- Code: ErrReleaseDeploy,
- Errors: []string{"error installing a new chart: " + err.Error()},
- }, w)
- return
- }
- w.WriteHeader(http.StatusOK)
- }
- // ------------------------ Deploy handler helper functions ------------------------ //
- func getDefaultValues(templateName string, baseURL string) (*map[interface{}]interface{}, error) {
- resp, err := http.Get(baseURL + "index.yaml")
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- defer resp.Body.Close()
- body, _ := ioutil.ReadAll(resp.Body)
- form := models.IndexYAML{}
- if err := yaml.Unmarshal([]byte(body), &form); err != nil {
- fmt.Println(err)
- return nil, err
- }
- // Loop over charts in index.yaml
- for k := range form.Entries {
- indexChart := form.Entries[k][0]
- tarURL := indexChart.Urls[0]
- splits := strings.Split(tarURL, "-")
- strAcc := splits[0]
- for i := 1; i < len(splits)-1; i++ {
- strAcc += "-" + splits[i]
- }
- // Unpack the target chart and retrieve values.yaml
- if strAcc == templateName {
- tgtURL := baseURL + tarURL
- values, err := processValues(tgtURL)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- return values, nil
- }
- }
- return nil, errors.New("no values.yaml found")
- }
- func processValues(tgtURL string) (*map[interface{}]interface{}, error) {
- resp, err := http.Get(tgtURL)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- defer resp.Body.Close()
- body, _ := ioutil.ReadAll(resp.Body)
- buf := bytes.NewBuffer(body)
- gzf, err := gzip.NewReader(buf)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- // Process tarball to generate FormYAML and retrieve markdown
- tarReader := tar.NewReader(gzf)
- for {
- header, err := tarReader.Next()
- if err == io.EOF {
- break
- } else if err != nil {
- fmt.Println(err)
- return nil, err
- }
- name := header.Name
- switch header.Typeflag {
- case tar.TypeDir:
- continue
- case tar.TypeReg:
- // Handle values.yaml located in archive
- if strings.Contains(name, "values.yaml") {
- bufForm := new(bytes.Buffer)
- _, err := io.Copy(bufForm, tarReader)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- // Unmarshal yaml byte buffer
- form := make(map[interface{}]interface{})
- if err := yaml.Unmarshal(bufForm.Bytes(), &form); err != nil {
- fmt.Println(err)
- return nil, err
- }
- return &form, nil
- }
- default:
- fmt.Printf("%s : %c %s %s\n",
- "Unknown type",
- header.Typeflag,
- "in file",
- name,
- )
- }
- }
- return nil, errors.New("no values.yaml found")
- }
|