github.com/migueleliasweb/helm@v2.6.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  		if err := ioutil.WriteFile(n, f.Value, 0755); err != nil {
    74  			return err
    75  		}
    76  	}
    77  
    78  	// Save dependencies
    79  	base := filepath.Join(outdir, ChartsDir)
    80  	for _, dep := range c.Dependencies {
    81  		// Here, we write each dependency as a tar file.
    82  		if _, err := Save(dep, base); err != nil {
    83  			return err
    84  		}
    85  	}
    86  	return nil
    87  }
    88  
    89  // Save creates an archived chart to the given directory.
    90  //
    91  // This takes an existing chart and a destination directory.
    92  //
    93  // If the directory is /foo, and the chart is named bar, with version 1.0.0, this
    94  // will generate /foo/bar-1.0.0.tgz.
    95  //
    96  // This returns the absolute path to the chart archive file.
    97  func Save(c *chart.Chart, outDir string) (string, error) {
    98  	// Create archive
    99  	if fi, err := os.Stat(outDir); err != nil {
   100  		return "", err
   101  	} else if !fi.IsDir() {
   102  		return "", fmt.Errorf("location %s is not a directory", outDir)
   103  	}
   104  
   105  	if c.Metadata == nil {
   106  		return "", errors.New("no Chart.yaml data")
   107  	}
   108  
   109  	cfile := c.Metadata
   110  	if cfile.Name == "" {
   111  		return "", errors.New("no chart name specified (Chart.yaml)")
   112  	} else if cfile.Version == "" {
   113  		return "", errors.New("no chart version specified (Chart.yaml)")
   114  	}
   115  
   116  	filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
   117  	filename = filepath.Join(outDir, filename)
   118  	f, err := os.Create(filename)
   119  	if err != nil {
   120  		return "", err
   121  	}
   122  
   123  	// Wrap in gzip writer
   124  	zipper := gzip.NewWriter(f)
   125  	zipper.Header.Extra = headerBytes
   126  	zipper.Header.Comment = "Helm"
   127  
   128  	// Wrap in tar writer
   129  	twriter := tar.NewWriter(zipper)
   130  	rollback := false
   131  	defer func() {
   132  		twriter.Close()
   133  		zipper.Close()
   134  		f.Close()
   135  		if rollback {
   136  			os.Remove(filename)
   137  		}
   138  	}()
   139  
   140  	if err := writeTarContents(twriter, c, ""); err != nil {
   141  		rollback = true
   142  	}
   143  	return filename, err
   144  }
   145  
   146  func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
   147  	base := filepath.Join(prefix, c.Metadata.Name)
   148  
   149  	// Save Chart.yaml
   150  	cdata, err := yaml.Marshal(c.Metadata)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
   155  		return err
   156  	}
   157  
   158  	// Save values.yaml
   159  	if c.Values != nil && len(c.Values.Raw) > 0 {
   160  		if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	// Save templates
   166  	for _, f := range c.Templates {
   167  		n := filepath.Join(base, f.Name)
   168  		if err := writeToTar(out, n, f.Data); err != nil {
   169  			return err
   170  		}
   171  	}
   172  
   173  	// Save files
   174  	for _, f := range c.Files {
   175  		n := filepath.Join(base, f.TypeUrl)
   176  		if err := writeToTar(out, n, f.Value); err != nil {
   177  			return err
   178  		}
   179  	}
   180  
   181  	// Save dependencies
   182  	for _, dep := range c.Dependencies {
   183  		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
   184  			return err
   185  		}
   186  	}
   187  	return nil
   188  }
   189  
   190  // writeToTar writes a single file to a tar archive.
   191  func writeToTar(out *tar.Writer, name string, body []byte) error {
   192  	// TODO: Do we need to create dummy parent directory names if none exist?
   193  	h := &tar.Header{
   194  		Name: name,
   195  		Mode: 0755,
   196  		Size: int64(len(body)),
   197  	}
   198  	if err := out.WriteHeader(h); err != nil {
   199  		return err
   200  	}
   201  	if _, err := out.Write(body); err != nil {
   202  		return err
   203  	}
   204  	return nil
   205  }