github.com/valdemarpavesi/helm@v2.9.1+incompatible/pkg/chartutil/save.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package chartutil
    18  
    19  import (
    20  	"archive/tar"
    21  	"compress/gzip"
    22  	"errors"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	"github.com/ghodss/yaml"
    29  
    30  	"k8s.io/helm/pkg/proto/hapi/chart"
    31  )
    32  
    33  var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")
    34  
    35  // SaveDir saves a chart as files in a directory.
    36  func SaveDir(c *chart.Chart, dest string) error {
    37  	// Create the chart directory
    38  	outdir := filepath.Join(dest, c.Metadata.Name)
    39  	if err := os.Mkdir(outdir, 0755); err != nil {
    40  		return err
    41  	}
    42  
    43  	// Save the chart file.
    44  	if err := SaveChartfile(filepath.Join(outdir, ChartfileName), c.Metadata); err != nil {
    45  		return err
    46  	}
    47  
    48  	// Save values.yaml
    49  	if c.Values != nil && len(c.Values.Raw) > 0 {
    50  		vf := filepath.Join(outdir, ValuesfileName)
    51  		if err := ioutil.WriteFile(vf, []byte(c.Values.Raw), 0755); err != nil {
    52  			return err
    53  		}
    54  	}
    55  
    56  	for _, d := range []string{TemplatesDir, ChartsDir} {
    57  		if err := os.MkdirAll(filepath.Join(outdir, d), 0755); err != nil {
    58  			return err
    59  		}
    60  	}
    61  
    62  	// Save templates
    63  	for _, f := range c.Templates {
    64  		n := filepath.Join(outdir, f.Name)
    65  		if err := ioutil.WriteFile(n, f.Data, 0755); err != nil {
    66  			return err
    67  		}
    68  	}
    69  
    70  	// Save files
    71  	for _, f := range c.Files {
    72  		n := filepath.Join(outdir, f.TypeUrl)
    73  
    74  		d := filepath.Dir(n)
    75  		if err := os.MkdirAll(d, 0755); err != nil {
    76  			return err
    77  		}
    78  
    79  		if err := ioutil.WriteFile(n, f.Value, 0755); err != nil {
    80  			return err
    81  		}
    82  	}
    83  
    84  	// Save dependencies
    85  	base := filepath.Join(outdir, ChartsDir)
    86  	for _, dep := range c.Dependencies {
    87  		// Here, we write each dependency as a tar file.
    88  		if _, err := Save(dep, base); err != nil {
    89  			return err
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  // Save creates an archived chart to the given directory.
    96  //
    97  // This takes an existing chart and a destination directory.
    98  //
    99  // If the directory is /foo, and the chart is named bar, with version 1.0.0, this
   100  // will generate /foo/bar-1.0.0.tgz.
   101  //
   102  // This returns the absolute path to the chart archive file.
   103  func Save(c *chart.Chart, outDir string) (string, error) {
   104  	// Create archive
   105  	if fi, err := os.Stat(outDir); err != nil {
   106  		return "", err
   107  	} else if !fi.IsDir() {
   108  		return "", fmt.Errorf("location %s is not a directory", outDir)
   109  	}
   110  
   111  	if c.Metadata == nil {
   112  		return "", errors.New("no Chart.yaml data")
   113  	}
   114  
   115  	cfile := c.Metadata
   116  	if cfile.Name == "" {
   117  		return "", errors.New("no chart name specified (Chart.yaml)")
   118  	} else if cfile.Version == "" {
   119  		return "", errors.New("no chart version specified (Chart.yaml)")
   120  	}
   121  
   122  	filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
   123  	filename = filepath.Join(outDir, filename)
   124  	if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
   125  		if err := os.MkdirAll(filepath.Dir(filename), 0755); !os.IsExist(err) {
   126  			return "", err
   127  		}
   128  	} else if !stat.IsDir() {
   129  		return "", fmt.Errorf("is not a directory: %s", filepath.Dir(filename))
   130  	}
   131  
   132  	f, err := os.Create(filename)
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  
   137  	// Wrap in gzip writer
   138  	zipper := gzip.NewWriter(f)
   139  	zipper.Header.Extra = headerBytes
   140  	zipper.Header.Comment = "Helm"
   141  
   142  	// Wrap in tar writer
   143  	twriter := tar.NewWriter(zipper)
   144  	rollback := false
   145  	defer func() {
   146  		twriter.Close()
   147  		zipper.Close()
   148  		f.Close()
   149  		if rollback {
   150  			os.Remove(filename)
   151  		}
   152  	}()
   153  
   154  	if err := writeTarContents(twriter, c, ""); err != nil {
   155  		rollback = true
   156  	}
   157  	return filename, err
   158  }
   159  
   160  func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
   161  	base := filepath.Join(prefix, c.Metadata.Name)
   162  
   163  	// Save Chart.yaml
   164  	cdata, err := yaml.Marshal(c.Metadata)
   165  	if err != nil {
   166  		return err
   167  	}
   168  	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
   169  		return err
   170  	}
   171  
   172  	// Save values.yaml
   173  	if c.Values != nil && len(c.Values.Raw) > 0 {
   174  		if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); err != nil {
   175  			return err
   176  		}
   177  	}
   178  
   179  	// Save templates
   180  	for _, f := range c.Templates {
   181  		n := filepath.Join(base, f.Name)
   182  		if err := writeToTar(out, n, f.Data); err != nil {
   183  			return err
   184  		}
   185  	}
   186  
   187  	// Save files
   188  	for _, f := range c.Files {
   189  		n := filepath.Join(base, f.TypeUrl)
   190  		if err := writeToTar(out, n, f.Value); err != nil {
   191  			return err
   192  		}
   193  	}
   194  
   195  	// Save dependencies
   196  	for _, dep := range c.Dependencies {
   197  		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
   198  			return err
   199  		}
   200  	}
   201  	return nil
   202  }
   203  
   204  // writeToTar writes a single file to a tar archive.
   205  func writeToTar(out *tar.Writer, name string, body []byte) error {
   206  	// TODO: Do we need to create dummy parent directory names if none exist?
   207  	h := &tar.Header{
   208  		Name: name,
   209  		Mode: 0755,
   210  		Size: int64(len(body)),
   211  	}
   212  	if err := out.WriteHeader(h); err != nil {
   213  		return err
   214  	}
   215  	if _, err := out.Write(body); err != nil {
   216  		return err
   217  	}
   218  	return nil
   219  }