| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- package api
- import (
- "archive/tar"
- "bytes"
- "compress/gzip"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "strings"
- "gopkg.in/yaml.v2"
- )
- // IndexYAML represents a chart repo's index.yaml
- type IndexYAML struct {
- APIVersion string `yaml:"apiVersion"`
- Generated string `yaml:"generated"`
- Entries map[interface{}]ChartYAML `yaml:"entries"`
- }
- // ChartYAML represents the data for chart in index.yaml
- type ChartYAML []struct {
- APIVersion string `yaml:"apiVersion"`
- AppVersion string `yaml:"appVersion"`
- Created string `yaml:"created"`
- Description string `yaml:"description"`
- Digest string `yaml:"digest"`
- Icon string `yaml:"icon"`
- Name string `yaml:"name"`
- Type string `yaml:"type"`
- Urls []string `yaml:"urls"`
- Version string `yaml:"version"`
- }
- // PorterChart represents a bundled Porter template
- type PorterChart struct {
- Name string
- Description string
- Icon string
- Form FormYAML
- Markdown string
- }
- // FormYAML represents a chart's values.yaml form abstraction
- type FormYAML struct {
- Name string `yaml:"name"`
- Icon string `yaml:"icon"`
- Description string `yaml:"description"`
- Tags []string `yaml:"tags"`
- Sections []struct {
- Name string `yaml:"name"`
- ShowIf string `yaml:"show_if"`
- Contents []struct {
- Type string `yaml:"type"`
- Label string `yaml:"label"`
- Name string `yaml:"name,omitempty"`
- Variable string `yaml:"variable,omitempty"`
- Settings struct {
- Default interface{}
- } `yaml:"settings,omitempty"`
- } `yaml:"contents"`
- } `yaml:"sections"`
- }
- // HandleListTemplates retrieves a list of Porter templates
- // TODO: test and reduce fragility (handle untar/parse error for individual charts)
- // TODO: separate markdown retrieval into its own query if necessary
- func (app *App) HandleListTemplates(w http.ResponseWriter, r *http.Request) {
- baseURL := "https://porter-dev.github.io/chart-repo/"
- resp, err := http.Get(baseURL + "index.yaml")
- if err != nil {
- fmt.Println(err)
- return
- }
- defer resp.Body.Close()
- body, _ := ioutil.ReadAll(resp.Body)
- form := IndexYAML{}
- if err := yaml.Unmarshal([]byte(body), &form); err != nil {
- fmt.Println(err)
- return
- }
- // Loop over charts in index.yaml
- porterCharts := []PorterChart{}
- for k := range form.Entries {
- indexChart := form.Entries[k][0]
- tarURL := indexChart.Urls[0]
- if !strings.Contains(tarURL, "http://") {
- tarURL = baseURL + tarURL
- }
- formData, markdown, err := processTarball(tarURL)
- if err != nil {
- fmt.Println(err)
- return
- }
- porterChart := PorterChart{}
- porterChart.Name = indexChart.Name
- porterChart.Description = indexChart.Description
- porterChart.Icon = indexChart.Icon
- porterChart.Form = *formData
- if markdown != "" {
- porterChart.Markdown = markdown
- }
- porterCharts = append(porterCharts, porterChart)
- }
- json.NewEncoder(w).Encode(porterCharts)
- }
- func processTarball(tarURL string) (*FormYAML, string, error) {
- resp, err := http.Get(tarURL)
- 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)
- markdown := ""
- 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 info.md if found
- if strings.Contains(name, "README.md") {
- bufMd := new(bytes.Buffer)
- _, err := io.Copy(bufMd, tarReader)
- if err != nil {
- fmt.Println(err)
- return nil, "", err
- }
- markdown = string(bufMd.Bytes())
- }
- // Handle form.yaml located in archive
- if strings.Contains(name, "form.yaml") {
- bufForm := new(bytes.Buffer)
- _, err := io.Copy(bufForm, tarReader)
- if err != nil {
- fmt.Println(err)
- return nil, "", err
- }
- // Unmarshal yaml byte buffer
- form := FormYAML{}
- if err := yaml.Unmarshal(bufForm.Bytes(), &form); err != nil {
- fmt.Println(err)
- return nil, "", err
- }
- return &form, markdown, nil
- }
- default:
- fmt.Printf("%s : %c %s %s\n",
- "Unknown type",
- header.Typeflag,
- "in file",
- name,
- )
- }
- }
- return nil, "", errors.New("no form.yaml found")
- }
|