mirror of https://github.com/helm/helm.git
				
				
				
			
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2016 The Kubernetes Authors All rights reserved.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package repo // import "k8s.io/helm/pkg/repo"
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/ghodss/yaml"
 | |
| 
 | |
| 	"k8s.io/helm/pkg/chartutil"
 | |
| 	"k8s.io/helm/pkg/provenance"
 | |
| 	"k8s.io/helm/pkg/tlsutil"
 | |
| )
 | |
| 
 | |
| // ChartRepositoryConfig represents a collection of parameters for chart repository
 | |
| type ChartRepositoryConfig struct {
 | |
| 	Name     string `json:"name"`
 | |
| 	Cache    string `json:"cache"`
 | |
| 	URL      string `json:"url"`
 | |
| 	CertFile string `json:"certFile"`
 | |
| 	KeyFile  string `json:"keyFile"`
 | |
| 	CAFile   string `json:"caFile"`
 | |
| }
 | |
| 
 | |
| // ChartRepository represents a chart repository
 | |
| type ChartRepository struct {
 | |
| 	Config     *ChartRepositoryConfig
 | |
| 	ChartPaths []string
 | |
| 	IndexFile  *ChartRepositoryIndex
 | |
| 	Client     *http.Client
 | |
| }
 | |
| 
 | |
| // NewChartRepository constructs ChartRepository
 | |
| func NewChartRepository(cfg *ChartRepositoryConfig) (*ChartRepository, error) {
 | |
| 	var client *http.Client
 | |
| 	if cfg.CertFile != "" && cfg.KeyFile != "" && cfg.CAFile != "" {
 | |
| 		tlsConf, err := tlsutil.NewClientTLS(cfg.CertFile, cfg.KeyFile, cfg.CAFile)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("can't create TLS config for client: %s", err.Error())
 | |
| 		}
 | |
| 		tlsConf.BuildNameToCertificate()
 | |
| 		client = &http.Client{
 | |
| 			Transport: &http.Transport{
 | |
| 				TLSClientConfig: tlsConf,
 | |
| 			},
 | |
| 		}
 | |
| 	} else {
 | |
| 		client = http.DefaultClient
 | |
| 	}
 | |
| 
 | |
| 	return &ChartRepository{
 | |
| 		Config:    cfg,
 | |
| 		IndexFile: NewChartRepositoryIndex(),
 | |
| 		Client:    client,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // Load loads a directory of charts as if it were a repository.
 | |
| //
 | |
| // It requires the presence of an index.yaml file in the directory.
 | |
| func (r *ChartRepository) Load() error {
 | |
| 	dirInfo, err := os.Stat(r.Config.Name)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if !dirInfo.IsDir() {
 | |
| 		return fmt.Errorf("%q is not a directory", r.Config.Name)
 | |
| 	}
 | |
| 
 | |
| 	// FIXME: Why are we recursively walking directories?
 | |
| 	// FIXME: Why are we not reading the repositories.yaml to figure out
 | |
| 	// what repos to use?
 | |
| 	filepath.Walk(r.Config.Name, func(path string, f os.FileInfo, err error) error {
 | |
| 		if !f.IsDir() {
 | |
| 			if strings.Contains(f.Name(), "-index.yaml") {
 | |
| 				i, err := NewChartRepositoryIndexFromFile(path)
 | |
| 				if err != nil {
 | |
| 					return nil
 | |
| 				}
 | |
| 				r.IndexFile = i
 | |
| 			} else if strings.HasSuffix(f.Name(), ".tgz") {
 | |
| 				r.ChartPaths = append(r.ChartPaths, path)
 | |
| 			}
 | |
| 		}
 | |
| 		return nil
 | |
| 	})
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // DownloadIndexFile fetches the index from a repository.
 | |
| func (r *ChartRepository) DownloadIndexFile() error {
 | |
| 	var indexURL string
 | |
| 
 | |
| 	indexURL = strings.TrimSuffix(r.Config.URL, "/") + "/index.yaml"
 | |
| 	resp, err := r.Client.Get(indexURL)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	index, err := ioutil.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if _, err := loadIndex(index); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return ioutil.WriteFile(r.Config.Cache, index, 0644)
 | |
| }
 | |
| 
 | |
| // Index generates an index for the chart repository and writes an index.yaml file.
 | |
| func (r *ChartRepository) Index() error {
 | |
| 	err := r.generateIndex()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return r.saveIndexFile()
 | |
| }
 | |
| 
 | |
| func (r *ChartRepository) saveIndexFile() error {
 | |
| 	index, err := yaml.Marshal(r.IndexFile)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return ioutil.WriteFile(filepath.Join(r.Config.Name, indexPath), index, 0644)
 | |
| }
 | |
| 
 | |
| func (r *ChartRepository) generateIndex() error {
 | |
| 	for _, path := range r.ChartPaths {
 | |
| 		ch, err := chartutil.Load(path)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		digest, err := provenance.DigestFile(path)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if !r.IndexFile.Has(ch.Metadata.Name, ch.Metadata.Version) {
 | |
| 			r.IndexFile.Add(ch.Metadata, path, r.Config.URL, digest)
 | |
| 		}
 | |
| 		// TODO: If a chart exists, but has a different Digest, should we error?
 | |
| 	}
 | |
| 	r.IndexFile.SortEntries()
 | |
| 	return nil
 | |
| }
 |