openpitrix crd
Signed-off-by: LiHui <andrewli@yunify.com> delete helm repo, release and app Signed-off-by: LiHui <andrewli@yunify.com> Fix Dockerfile Signed-off-by: LiHui <andrewli@yunify.com> add unit test for category controller Signed-off-by: LiHui <andrewli@yunify.com> resource api Signed-off-by: LiHui <andrewli@yunify.com> miscellaneous Signed-off-by: LiHui <andrewli@yunify.com> resource api Signed-off-by: LiHui <andrewli@yunify.com> add s3 repo indx Signed-off-by: LiHui <andrewli@yunify.com> attachment api Signed-off-by: LiHui <andrewli@yunify.com> repo controller test Signed-off-by: LiHui <andrewli@yunify.com> application controller test Signed-off-by: LiHui <andrewli@yunify.com> release metric Signed-off-by: LiHui <andrewli@yunify.com> helm release controller test Signed-off-by: LiHui <andrewli@yunify.com> move constants to /pkg/apis/application Signed-off-by: LiHui <andrewli@yunify.com> remove unused code Signed-off-by: LiHui <andrewli@yunify.com> add license header Signed-off-by: LiHui <andrewli@yunify.com> Fix bugs Signed-off-by: LiHui <andrewli@yunify.com> cluster cluent Signed-off-by: LiHui <andrewli@yunify.com> format code Signed-off-by: LiHui <andrewli@yunify.com> move workspace,cluster from spec to labels Signed-off-by: LiHui <andrewli@yunify.com> add license header Signed-off-by: LiHui <andrewli@yunify.com> openpitrix test Signed-off-by: LiHui <andrewli@yunify.com> add worksapce labels for app in appstore Signed-off-by: LiHui <andrewli@yunify.com>
This commit is contained in:
169
vendor/helm.sh/helm/v3/pkg/chart/chart.go
vendored
Normal file
169
vendor/helm.sh/helm/v3/pkg/chart/chart.go
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// APIVersionV1 is the API version number for version 1.
|
||||
const APIVersionV1 = "v1"
|
||||
|
||||
// APIVersionV2 is the API version number for version 2.
|
||||
const APIVersionV2 = "v2"
|
||||
|
||||
// Chart is a helm package that contains metadata, a default config, zero or more
|
||||
// optionally parameterizable templates, and zero or more charts (dependencies).
|
||||
type Chart struct {
|
||||
// Raw contains the raw contents of the files originally contained in the chart archive.
|
||||
//
|
||||
// This should not be used except in special cases like `helm show values`,
|
||||
// where we want to display the raw values, comments and all.
|
||||
Raw []*File `json:"-"`
|
||||
// Metadata is the contents of the Chartfile.
|
||||
Metadata *Metadata `json:"metadata"`
|
||||
// Lock is the contents of Chart.lock.
|
||||
Lock *Lock `json:"lock"`
|
||||
// Templates for this chart.
|
||||
Templates []*File `json:"templates"`
|
||||
// Values are default config for this chart.
|
||||
Values map[string]interface{} `json:"values"`
|
||||
// Schema is an optional JSON schema for imposing structure on Values
|
||||
Schema []byte `json:"schema"`
|
||||
// Files are miscellaneous files in a chart archive,
|
||||
// e.g. README, LICENSE, etc.
|
||||
Files []*File `json:"files"`
|
||||
|
||||
parent *Chart
|
||||
dependencies []*Chart
|
||||
}
|
||||
|
||||
type CRD struct {
|
||||
// Name is the File.Name for the crd file
|
||||
Name string
|
||||
// Filename is the File obj Name including (sub-)chart.ChartFullPath
|
||||
Filename string
|
||||
// File is the File obj for the crd
|
||||
File *File
|
||||
}
|
||||
|
||||
// SetDependencies replaces the chart dependencies.
|
||||
func (ch *Chart) SetDependencies(charts ...*Chart) {
|
||||
ch.dependencies = nil
|
||||
ch.AddDependency(charts...)
|
||||
}
|
||||
|
||||
// Name returns the name of the chart.
|
||||
func (ch *Chart) Name() string {
|
||||
if ch.Metadata == nil {
|
||||
return ""
|
||||
}
|
||||
return ch.Metadata.Name
|
||||
}
|
||||
|
||||
// AddDependency determines if the chart is a subchart.
|
||||
func (ch *Chart) AddDependency(charts ...*Chart) {
|
||||
for i, x := range charts {
|
||||
charts[i].parent = ch
|
||||
ch.dependencies = append(ch.dependencies, x)
|
||||
}
|
||||
}
|
||||
|
||||
// Root finds the root chart.
|
||||
func (ch *Chart) Root() *Chart {
|
||||
if ch.IsRoot() {
|
||||
return ch
|
||||
}
|
||||
return ch.Parent().Root()
|
||||
}
|
||||
|
||||
// Dependencies are the charts that this chart depends on.
|
||||
func (ch *Chart) Dependencies() []*Chart { return ch.dependencies }
|
||||
|
||||
// IsRoot determines if the chart is the root chart.
|
||||
func (ch *Chart) IsRoot() bool { return ch.parent == nil }
|
||||
|
||||
// Parent returns a subchart's parent chart.
|
||||
func (ch *Chart) Parent() *Chart { return ch.parent }
|
||||
|
||||
// ChartPath returns the full path to this chart in dot notation.
|
||||
func (ch *Chart) ChartPath() string {
|
||||
if !ch.IsRoot() {
|
||||
return ch.Parent().ChartPath() + "." + ch.Name()
|
||||
}
|
||||
return ch.Name()
|
||||
}
|
||||
|
||||
// ChartFullPath returns the full path to this chart.
|
||||
func (ch *Chart) ChartFullPath() string {
|
||||
if !ch.IsRoot() {
|
||||
return ch.Parent().ChartFullPath() + "/charts/" + ch.Name()
|
||||
}
|
||||
return ch.Name()
|
||||
}
|
||||
|
||||
// Validate validates the metadata.
|
||||
func (ch *Chart) Validate() error {
|
||||
return ch.Metadata.Validate()
|
||||
}
|
||||
|
||||
// AppVersion returns the appversion of the chart.
|
||||
func (ch *Chart) AppVersion() string {
|
||||
if ch.Metadata == nil {
|
||||
return ""
|
||||
}
|
||||
return ch.Metadata.AppVersion
|
||||
}
|
||||
|
||||
// CRDs returns a list of File objects in the 'crds/' directory of a Helm chart.
|
||||
// Deprecated: use CRDObjects()
|
||||
func (ch *Chart) CRDs() []*File {
|
||||
files := []*File{}
|
||||
// Find all resources in the crds/ directory
|
||||
for _, f := range ch.Files {
|
||||
if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) {
|
||||
files = append(files, f)
|
||||
}
|
||||
}
|
||||
// Get CRDs from dependencies, too.
|
||||
for _, dep := range ch.Dependencies() {
|
||||
files = append(files, dep.CRDs()...)
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// CRDObjects returns a list of CRD objects in the 'crds/' directory of a Helm chart & subcharts
|
||||
func (ch *Chart) CRDObjects() []CRD {
|
||||
crds := []CRD{}
|
||||
// Find all resources in the crds/ directory
|
||||
for _, f := range ch.Files {
|
||||
if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) {
|
||||
mycrd := CRD{Name: f.Name, Filename: filepath.Join(ch.ChartFullPath(), f.Name), File: f}
|
||||
crds = append(crds, mycrd)
|
||||
}
|
||||
}
|
||||
// Get CRDs from dependencies, too.
|
||||
for _, dep := range ch.Dependencies() {
|
||||
crds = append(crds, dep.CRDObjects()...)
|
||||
}
|
||||
return crds
|
||||
}
|
||||
|
||||
func hasManifestExtension(fname string) bool {
|
||||
ext := filepath.Ext(fname)
|
||||
return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".json")
|
||||
}
|
||||
62
vendor/helm.sh/helm/v3/pkg/chart/dependency.go
vendored
Normal file
62
vendor/helm.sh/helm/v3/pkg/chart/dependency.go
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
import "time"
|
||||
|
||||
// Dependency describes a chart upon which another chart depends.
|
||||
//
|
||||
// Dependencies can be used to express developer intent, or to capture the state
|
||||
// of a chart.
|
||||
type Dependency struct {
|
||||
// Name is the name of the dependency.
|
||||
//
|
||||
// This must mach the name in the dependency's Chart.yaml.
|
||||
Name string `json:"name"`
|
||||
// Version is the version (range) of this chart.
|
||||
//
|
||||
// A lock file will always produce a single version, while a dependency
|
||||
// may contain a semantic version range.
|
||||
Version string `json:"version,omitempty"`
|
||||
// The URL to the repository.
|
||||
//
|
||||
// Appending `index.yaml` to this string should result in a URL that can be
|
||||
// used to fetch the repository index.
|
||||
Repository string `json:"repository"`
|
||||
// A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// Tags can be used to group charts for enabling/disabling together
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Enabled bool determines if chart should be loaded
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
// ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
|
||||
// string or pair of child/parent sublist items.
|
||||
ImportValues []interface{} `json:"import-values,omitempty"`
|
||||
// Alias usable alias to be used for the chart
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// Lock is a lock file for dependencies.
|
||||
//
|
||||
// It represents the state that the dependencies should be in.
|
||||
type Lock struct {
|
||||
// Generated is the date the lock file was last generated.
|
||||
Generated time.Time `json:"generated"`
|
||||
// Digest is a hash of the dependencies in Chart.yaml.
|
||||
Digest string `json:"digest"`
|
||||
// Dependencies is the list of dependencies that this lock file has locked.
|
||||
Dependencies []*Dependency `json:"dependencies"`
|
||||
}
|
||||
23
vendor/helm.sh/helm/v3/pkg/chart/errors.go
vendored
Normal file
23
vendor/helm.sh/helm/v3/pkg/chart/errors.go
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// ValidationError represents a data validation error.
|
||||
type ValidationError string
|
||||
|
||||
func (v ValidationError) Error() string {
|
||||
return "validation: " + string(v)
|
||||
}
|
||||
27
vendor/helm.sh/helm/v3/pkg/chart/file.go
vendored
Normal file
27
vendor/helm.sh/helm/v3/pkg/chart/file.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// File represents a file as a name/value pair.
|
||||
//
|
||||
// By convention, name is a relative path within the scope of the chart's
|
||||
// base directory.
|
||||
type File struct {
|
||||
// Name is the path-like name of the template.
|
||||
Name string `json:"name"`
|
||||
// Data is the template as byte data.
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
196
vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go
vendored
Normal file
196
vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`)
|
||||
|
||||
// FileLoader loads a chart from a file
|
||||
type FileLoader string
|
||||
|
||||
// Load loads a chart
|
||||
func (l FileLoader) Load() (*chart.Chart, error) {
|
||||
return LoadFile(string(l))
|
||||
}
|
||||
|
||||
// LoadFile loads from an archive file.
|
||||
func LoadFile(name string) (*chart.Chart, error) {
|
||||
if fi, err := os.Stat(name); err != nil {
|
||||
return nil, err
|
||||
} else if fi.IsDir() {
|
||||
return nil, errors.New("cannot load a directory")
|
||||
}
|
||||
|
||||
raw, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer raw.Close()
|
||||
|
||||
err = ensureArchive(name, raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := LoadArchive(raw)
|
||||
if err != nil {
|
||||
if err == gzip.ErrHeader {
|
||||
return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err)
|
||||
}
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
// ensureArchive's job is to return an informative error if the file does not appear to be a gzipped archive.
|
||||
//
|
||||
// Sometimes users will provide a values.yaml for an argument where a chart is expected. One common occurrence
|
||||
// of this is invoking `helm template values.yaml mychart` which would otherwise produce a confusing error
|
||||
// if we didn't check for this.
|
||||
func ensureArchive(name string, raw *os.File) error {
|
||||
defer raw.Seek(0, 0) // reset read offset to allow archive loading to proceed.
|
||||
|
||||
// Check the file format to give us a chance to provide the user with more actionable feedback.
|
||||
buffer := make([]byte, 512)
|
||||
_, err := raw.Read(buffer)
|
||||
if err != nil && err != io.EOF {
|
||||
return fmt.Errorf("file '%s' cannot be read: %s", name, err)
|
||||
}
|
||||
if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" {
|
||||
// TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide
|
||||
// variety of content (Makefile, .zshrc) as valid YAML without errors.
|
||||
|
||||
// Wrong content type. Let's check if it's yaml and give an extra hint?
|
||||
if strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") {
|
||||
return fmt.Errorf("file '%s' seems to be a YAML file, but expected a gzipped archive", name)
|
||||
}
|
||||
return fmt.Errorf("file '%s' does not appear to be a gzipped archive; got '%s'", name, contentType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadArchiveFiles reads in files out of an archive into memory. This function
|
||||
// performs important path security checks and should always be used before
|
||||
// expanding a tarball
|
||||
func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
|
||||
unzipped, err := gzip.NewReader(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer unzipped.Close()
|
||||
|
||||
files := []*BufferedFile{}
|
||||
tr := tar.NewReader(unzipped)
|
||||
for {
|
||||
b := bytes.NewBuffer(nil)
|
||||
hd, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hd.FileInfo().IsDir() {
|
||||
// Use this instead of hd.Typeflag because we don't have to do any
|
||||
// inference chasing.
|
||||
continue
|
||||
}
|
||||
|
||||
switch hd.Typeflag {
|
||||
// We don't want to process these extension header files.
|
||||
case tar.TypeXGlobalHeader, tar.TypeXHeader:
|
||||
continue
|
||||
}
|
||||
|
||||
// Archive could contain \ if generated on Windows
|
||||
delimiter := "/"
|
||||
if strings.ContainsRune(hd.Name, '\\') {
|
||||
delimiter = "\\"
|
||||
}
|
||||
|
||||
parts := strings.Split(hd.Name, delimiter)
|
||||
n := strings.Join(parts[1:], delimiter)
|
||||
|
||||
// Normalize the path to the / delimiter
|
||||
n = strings.ReplaceAll(n, delimiter, "/")
|
||||
|
||||
if path.IsAbs(n) {
|
||||
return nil, errors.New("chart illegally contains absolute paths")
|
||||
}
|
||||
|
||||
n = path.Clean(n)
|
||||
if n == "." {
|
||||
// In this case, the original path was relative when it should have been absolute.
|
||||
return nil, errors.Errorf("chart illegally contains content outside the base directory: %q", hd.Name)
|
||||
}
|
||||
if strings.HasPrefix(n, "..") {
|
||||
return nil, errors.New("chart illegally references parent directory")
|
||||
}
|
||||
|
||||
// In some particularly arcane acts of path creativity, it is possible to intermix
|
||||
// UNIX and Windows style paths in such a way that you produce a result of the form
|
||||
// c:/foo even after all the built-in absolute path checks. So we explicitly check
|
||||
// for this condition.
|
||||
if drivePathPattern.MatchString(n) {
|
||||
return nil, errors.New("chart contains illegally named files")
|
||||
}
|
||||
|
||||
if parts[0] == "Chart.yaml" {
|
||||
return nil, errors.New("chart yaml not in base directory")
|
||||
}
|
||||
|
||||
if _, err := io.Copy(b, tr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := bytes.TrimPrefix(b.Bytes(), utf8bom)
|
||||
|
||||
files = append(files, &BufferedFile{Name: n, Data: data})
|
||||
b.Reset()
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, errors.New("no files in chart archive")
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// LoadArchive loads from a reader containing a compressed tar archive.
|
||||
func LoadArchive(in io.Reader) (*chart.Chart, error) {
|
||||
files, err := LoadArchiveFiles(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return LoadFiles(files)
|
||||
}
|
||||
120
vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go
vendored
Normal file
120
vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/internal/ignore"
|
||||
"helm.sh/helm/v3/internal/sympath"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
var utf8bom = []byte{0xEF, 0xBB, 0xBF}
|
||||
|
||||
// DirLoader loads a chart from a directory
|
||||
type DirLoader string
|
||||
|
||||
// Load loads the chart
|
||||
func (l DirLoader) Load() (*chart.Chart, error) {
|
||||
return LoadDir(string(l))
|
||||
}
|
||||
|
||||
// LoadDir loads from a directory.
|
||||
//
|
||||
// This loads charts only from directories.
|
||||
func LoadDir(dir string) (*chart.Chart, error) {
|
||||
topdir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Just used for errors.
|
||||
c := &chart.Chart{}
|
||||
|
||||
rules := ignore.Empty()
|
||||
ifile := filepath.Join(topdir, ignore.HelmIgnore)
|
||||
if _, err := os.Stat(ifile); err == nil {
|
||||
r, err := ignore.ParseFile(ifile)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
rules = r
|
||||
}
|
||||
rules.AddDefaults()
|
||||
|
||||
files := []*BufferedFile{}
|
||||
topdir += string(filepath.Separator)
|
||||
|
||||
walk := func(name string, fi os.FileInfo, err error) error {
|
||||
n := strings.TrimPrefix(name, topdir)
|
||||
if n == "" {
|
||||
// No need to process top level. Avoid bug with helmignore .* matching
|
||||
// empty names. See issue 1779.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalize to / since it will also work on Windows
|
||||
n = filepath.ToSlash(n)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// Directory-based ignore rules should involve skipping the entire
|
||||
// contents of that directory.
|
||||
if rules.Ignore(n, fi) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If a .helmignore file matches, skip this file.
|
||||
if rules.Ignore(n, fi) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Irregular files include devices, sockets, and other uses of files that
|
||||
// are not regular files. In Go they have a file mode type bit set.
|
||||
// See https://golang.org/pkg/os/#FileMode for examples.
|
||||
if !fi.Mode().IsRegular() {
|
||||
return fmt.Errorf("cannot load irregular file %s as it has file mode type bits set", name)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading %s", n)
|
||||
}
|
||||
|
||||
data = bytes.TrimPrefix(data, utf8bom)
|
||||
|
||||
files = append(files, &BufferedFile{Name: n, Data: data})
|
||||
return nil
|
||||
}
|
||||
if err = sympath.Walk(topdir, walk); err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
return LoadFiles(files)
|
||||
}
|
||||
185
vendor/helm.sh/helm/v3/pkg/chart/loader/load.go
vendored
Normal file
185
vendor/helm.sh/helm/v3/pkg/chart/loader/load.go
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// ChartLoader loads a chart.
|
||||
type ChartLoader interface {
|
||||
Load() (*chart.Chart, error)
|
||||
}
|
||||
|
||||
// Loader returns a new ChartLoader appropriate for the given chart name
|
||||
func Loader(name string) (ChartLoader, error) {
|
||||
fi, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return DirLoader(name), nil
|
||||
}
|
||||
return FileLoader(name), nil
|
||||
|
||||
}
|
||||
|
||||
// Load takes a string name, tries to resolve it to a file or directory, and then loads it.
|
||||
//
|
||||
// This is the preferred way to load a chart. It will discover the chart encoding
|
||||
// and hand off to the appropriate chart reader.
|
||||
//
|
||||
// If a .helmignore file is present, the directory loader will skip loading any files
|
||||
// matching it. But .helmignore is not evaluated when reading out of an archive.
|
||||
func Load(name string) (*chart.Chart, error) {
|
||||
l, err := Loader(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l.Load()
|
||||
}
|
||||
|
||||
// BufferedFile represents an archive file buffered for later processing.
|
||||
type BufferedFile struct {
|
||||
Name string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// LoadFiles loads from in-memory files.
|
||||
func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
|
||||
c := new(chart.Chart)
|
||||
subcharts := make(map[string][]*BufferedFile)
|
||||
|
||||
for _, f := range files {
|
||||
c.Raw = append(c.Raw, &chart.File{Name: f.Name, Data: f.Data})
|
||||
switch {
|
||||
case f.Name == "Chart.yaml":
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = new(chart.Metadata)
|
||||
}
|
||||
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load Chart.yaml")
|
||||
}
|
||||
// NOTE(bacongobbler): while the chart specification says that APIVersion must be set,
|
||||
// Helm 2 accepted charts that did not provide an APIVersion in their chart metadata.
|
||||
// Because of that, if APIVersion is unset, we should assume we're loading a v1 chart.
|
||||
if c.Metadata.APIVersion == "" {
|
||||
c.Metadata.APIVersion = chart.APIVersionV1
|
||||
}
|
||||
case f.Name == "Chart.lock":
|
||||
c.Lock = new(chart.Lock)
|
||||
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load Chart.lock")
|
||||
}
|
||||
case f.Name == "values.yaml":
|
||||
c.Values = make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(f.Data, &c.Values); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load values.yaml")
|
||||
}
|
||||
case f.Name == "values.schema.json":
|
||||
c.Schema = f.Data
|
||||
|
||||
// Deprecated: requirements.yaml is deprecated use Chart.yaml.
|
||||
// We will handle it for you because we are nice people
|
||||
case f.Name == "requirements.yaml":
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = new(chart.Metadata)
|
||||
}
|
||||
if c.Metadata.APIVersion != chart.APIVersionV1 {
|
||||
log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.")
|
||||
}
|
||||
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load requirements.yaml")
|
||||
}
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
// Deprecated: requirements.lock is deprecated use Chart.lock.
|
||||
case f.Name == "requirements.lock":
|
||||
c.Lock = new(chart.Lock)
|
||||
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load requirements.lock")
|
||||
}
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
|
||||
case strings.HasPrefix(f.Name, "templates/"):
|
||||
c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data})
|
||||
case strings.HasPrefix(f.Name, "charts/"):
|
||||
if filepath.Ext(f.Name) == ".prov" {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
continue
|
||||
}
|
||||
|
||||
fname := strings.TrimPrefix(f.Name, "charts/")
|
||||
cname := strings.SplitN(fname, "/", 2)[0]
|
||||
subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data})
|
||||
default:
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.Validate(); err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
for n, files := range subcharts {
|
||||
var sc *chart.Chart
|
||||
var err error
|
||||
switch {
|
||||
case strings.IndexAny(n, "_.") == 0:
|
||||
continue
|
||||
case filepath.Ext(n) == ".tgz":
|
||||
file := files[0]
|
||||
if file.Name != n {
|
||||
return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name)
|
||||
}
|
||||
// Untar the chart and add to c.Dependencies
|
||||
sc, err = LoadArchive(bytes.NewBuffer(file.Data))
|
||||
default:
|
||||
// We have to trim the prefix off of every file, and ignore any file
|
||||
// that is in charts/, but isn't actually a chart.
|
||||
buff := make([]*BufferedFile, 0, len(files))
|
||||
for _, f := range files {
|
||||
parts := strings.SplitN(f.Name, "/", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
f.Name = parts[1]
|
||||
buff = append(buff, f)
|
||||
}
|
||||
sc, err = LoadFiles(buff)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name())
|
||||
}
|
||||
c.AddDependency(sc)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
94
vendor/helm.sh/helm/v3/pkg/chart/metadata.go
vendored
Normal file
94
vendor/helm.sh/helm/v3/pkg/chart/metadata.go
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// Maintainer describes a Chart maintainer.
|
||||
type Maintainer struct {
|
||||
// Name is a user name or organization name
|
||||
Name string `json:"name,omitempty"`
|
||||
// Email is an optional email address to contact the named maintainer
|
||||
Email string `json:"email,omitempty"`
|
||||
// URL is an optional URL to an address for the named maintainer
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
|
||||
type Metadata struct {
|
||||
// The name of the chart
|
||||
Name string `json:"name,omitempty"`
|
||||
// The URL to a relevant project page, git repo, or contact person
|
||||
Home string `json:"home,omitempty"`
|
||||
// Source is the URL to the source code of this chart
|
||||
Sources []string `json:"sources,omitempty"`
|
||||
// A SemVer 2 conformant version string of the chart
|
||||
Version string `json:"version,omitempty"`
|
||||
// A one-sentence description of the chart
|
||||
Description string `json:"description,omitempty"`
|
||||
// A list of string keywords
|
||||
Keywords []string `json:"keywords,omitempty"`
|
||||
// A list of name and URL/email address combinations for the maintainer(s)
|
||||
Maintainers []*Maintainer `json:"maintainers,omitempty"`
|
||||
// The URL to an icon file.
|
||||
Icon string `json:"icon,omitempty"`
|
||||
// The API Version of this chart.
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
// The condition to check to enable chart
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// The tags to check to enable chart
|
||||
Tags string `json:"tags,omitempty"`
|
||||
// The version of the application enclosed inside of this chart.
|
||||
AppVersion string `json:"appVersion,omitempty"`
|
||||
// Whether or not this chart is deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// Annotations are additional mappings uninterpreted by Helm,
|
||||
// made available for inspection by other applications.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
|
||||
KubeVersion string `json:"kubeVersion,omitempty"`
|
||||
// Dependencies are a list of dependencies for a chart.
|
||||
Dependencies []*Dependency `json:"dependencies,omitempty"`
|
||||
// Specifies the chart type: application or library
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the metadata for known issues, returning an error if metadata is not correct
|
||||
func (md *Metadata) Validate() error {
|
||||
if md == nil {
|
||||
return ValidationError("chart.metadata is required")
|
||||
}
|
||||
if md.APIVersion == "" {
|
||||
return ValidationError("chart.metadata.apiVersion is required")
|
||||
}
|
||||
if md.Name == "" {
|
||||
return ValidationError("chart.metadata.name is required")
|
||||
}
|
||||
if md.Version == "" {
|
||||
return ValidationError("chart.metadata.version is required")
|
||||
}
|
||||
if !isValidChartType(md.Type) {
|
||||
return ValidationError("chart.metadata.type must be application or library")
|
||||
}
|
||||
// TODO validate valid semver here?
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidChartType(in string) bool {
|
||||
switch in {
|
||||
case "", "application", "library":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
140
vendor/helm.sh/helm/v3/pkg/cli/environment.go
vendored
Normal file
140
vendor/helm.sh/helm/v3/pkg/cli/environment.go
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 cli describes the operating environment for the Helm CLI.
|
||||
|
||||
Helm's environment encapsulates all of the service dependencies Helm has.
|
||||
These dependencies are expressed as interfaces so that alternate implementations
|
||||
(mocks, etc.) can be easily generated.
|
||||
*/
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
|
||||
"helm.sh/helm/v3/pkg/helmpath"
|
||||
)
|
||||
|
||||
// EnvSettings describes all of the environment settings.
|
||||
type EnvSettings struct {
|
||||
namespace string
|
||||
config *genericclioptions.ConfigFlags
|
||||
|
||||
// KubeConfig is the path to the kubeconfig file
|
||||
KubeConfig string
|
||||
// KubeContext is the name of the kubeconfig context.
|
||||
KubeContext string
|
||||
// Bearer KubeToken used for authentication
|
||||
KubeToken string
|
||||
// Kubernetes API Server Endpoint for authentication
|
||||
KubeAPIServer string
|
||||
// Debug indicates whether or not Helm is running in Debug mode.
|
||||
Debug bool
|
||||
// RegistryConfig is the path to the registry config file.
|
||||
RegistryConfig string
|
||||
// RepositoryConfig is the path to the repositories file.
|
||||
RepositoryConfig string
|
||||
// RepositoryCache is the path to the repository cache directory.
|
||||
RepositoryCache string
|
||||
// PluginsDirectory is the path to the plugins directory.
|
||||
PluginsDirectory string
|
||||
}
|
||||
|
||||
func New() *EnvSettings {
|
||||
env := &EnvSettings{
|
||||
namespace: os.Getenv("HELM_NAMESPACE"),
|
||||
KubeContext: os.Getenv("HELM_KUBECONTEXT"),
|
||||
KubeToken: os.Getenv("HELM_KUBETOKEN"),
|
||||
KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"),
|
||||
PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")),
|
||||
RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry.json")),
|
||||
RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")),
|
||||
RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")),
|
||||
}
|
||||
env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG"))
|
||||
|
||||
// bind to kubernetes config flags
|
||||
env.config = &genericclioptions.ConfigFlags{
|
||||
Namespace: &env.namespace,
|
||||
Context: &env.KubeContext,
|
||||
BearerToken: &env.KubeToken,
|
||||
APIServer: &env.KubeAPIServer,
|
||||
KubeConfig: &env.KubeConfig,
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
// AddFlags binds flags to the given flagset.
|
||||
func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request")
|
||||
fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file")
|
||||
fs.StringVar(&s.KubeContext, "kube-context", s.KubeContext, "name of the kubeconfig context to use")
|
||||
fs.StringVar(&s.KubeToken, "kube-token", s.KubeToken, "bearer token used for authentication")
|
||||
fs.StringVar(&s.KubeAPIServer, "kube-apiserver", s.KubeAPIServer, "the address and the port for the Kubernetes API server")
|
||||
fs.BoolVar(&s.Debug, "debug", s.Debug, "enable verbose output")
|
||||
fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file")
|
||||
fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs")
|
||||
fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes")
|
||||
}
|
||||
|
||||
func envOr(name, def string) string {
|
||||
if v, ok := os.LookupEnv(name); ok {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func (s *EnvSettings) EnvVars() map[string]string {
|
||||
envvars := map[string]string{
|
||||
"HELM_BIN": os.Args[0],
|
||||
"HELM_CACHE_HOME": helmpath.CachePath(""),
|
||||
"HELM_CONFIG_HOME": helmpath.ConfigPath(""),
|
||||
"HELM_DATA_HOME": helmpath.DataPath(""),
|
||||
"HELM_DEBUG": fmt.Sprint(s.Debug),
|
||||
"HELM_PLUGINS": s.PluginsDirectory,
|
||||
"HELM_REGISTRY_CONFIG": s.RegistryConfig,
|
||||
"HELM_REPOSITORY_CACHE": s.RepositoryCache,
|
||||
"HELM_REPOSITORY_CONFIG": s.RepositoryConfig,
|
||||
"HELM_NAMESPACE": s.Namespace(),
|
||||
|
||||
// broken, these are populated from helm flags and not kubeconfig.
|
||||
"HELM_KUBECONTEXT": s.KubeContext,
|
||||
"HELM_KUBETOKEN": s.KubeToken,
|
||||
"HELM_KUBEAPISERVER": s.KubeAPIServer,
|
||||
}
|
||||
if s.KubeConfig != "" {
|
||||
envvars["KUBECONFIG"] = s.KubeConfig
|
||||
}
|
||||
return envvars
|
||||
}
|
||||
|
||||
// Namespace gets the namespace from the configuration
|
||||
func (s *EnvSettings) Namespace() string {
|
||||
if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil {
|
||||
return ns
|
||||
}
|
||||
return "default"
|
||||
}
|
||||
|
||||
// RESTClientGetter gets the kubeconfig from EnvSettings
|
||||
func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter {
|
||||
return s.config
|
||||
}
|
||||
21
vendor/helm.sh/helm/v3/pkg/getter/doc.go
vendored
Normal file
21
vendor/helm.sh/helm/v3/pkg/getter/doc.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter provides a generalize tool for fetching data by scheme.
|
||||
|
||||
This provides a method by which the plugin system can load arbitrary protocol
|
||||
handlers based upon a URL scheme.
|
||||
*/
|
||||
package getter
|
||||
150
vendor/helm.sh/helm/v3/pkg/getter/getter.go
vendored
Normal file
150
vendor/helm.sh/helm/v3/pkg/getter/getter.go
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
)
|
||||
|
||||
// options are generic parameters to be provided to the getter during instantiation.
|
||||
//
|
||||
// Getters may or may not ignore these parameters as they are passed in.
|
||||
type options struct {
|
||||
url string
|
||||
certFile string
|
||||
keyFile string
|
||||
caFile string
|
||||
insecureSkipVerifyTLS bool
|
||||
username string
|
||||
password string
|
||||
userAgent string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// Option allows specifying various settings configurable by the user for overriding the defaults
|
||||
// used when performing Get operations with the Getter.
|
||||
type Option func(*options)
|
||||
|
||||
// WithURL informs the getter the server name that will be used when fetching objects. Used in conjunction with
|
||||
// WithTLSClientConfig to set the TLSClientConfig's server name.
|
||||
func WithURL(url string) Option {
|
||||
return func(opts *options) {
|
||||
opts.url = url
|
||||
}
|
||||
}
|
||||
|
||||
// WithBasicAuth sets the request's Authorization header to use the provided credentials
|
||||
func WithBasicAuth(username, password string) Option {
|
||||
return func(opts *options) {
|
||||
opts.username = username
|
||||
opts.password = password
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserAgent sets the request's User-Agent header to use the provided agent name.
|
||||
func WithUserAgent(userAgent string) Option {
|
||||
return func(opts *options) {
|
||||
opts.userAgent = userAgent
|
||||
}
|
||||
}
|
||||
|
||||
// WithInsecureSkipVerifyTLS determines if a TLS Certificate will be checked
|
||||
func WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) Option {
|
||||
return func(opts *options) {
|
||||
opts.insecureSkipVerifyTLS = insecureSkipVerifyTLS
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSClientConfig sets the client auth with the provided credentials.
|
||||
func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
|
||||
return func(opts *options) {
|
||||
opts.certFile = certFile
|
||||
opts.keyFile = keyFile
|
||||
opts.caFile = caFile
|
||||
}
|
||||
}
|
||||
|
||||
// WithTimeout sets the timeout for requests
|
||||
func WithTimeout(timeout time.Duration) Option {
|
||||
return func(opts *options) {
|
||||
opts.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// Getter is an interface to support GET to the specified URL.
|
||||
type Getter interface {
|
||||
// Get file content by url string
|
||||
Get(url string, options ...Option) (*bytes.Buffer, error)
|
||||
}
|
||||
|
||||
// Constructor is the function for every getter which creates a specific instance
|
||||
// according to the configuration
|
||||
type Constructor func(options ...Option) (Getter, error)
|
||||
|
||||
// Provider represents any getter and the schemes that it supports.
|
||||
//
|
||||
// For example, an HTTP provider may provide one getter that handles both
|
||||
// 'http' and 'https' schemes.
|
||||
type Provider struct {
|
||||
Schemes []string
|
||||
New Constructor
|
||||
}
|
||||
|
||||
// Provides returns true if the given scheme is supported by this Provider.
|
||||
func (p Provider) Provides(scheme string) bool {
|
||||
for _, i := range p.Schemes {
|
||||
if i == scheme {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Providers is a collection of Provider objects.
|
||||
type Providers []Provider
|
||||
|
||||
// ByScheme returns a Provider that handles the given scheme.
|
||||
//
|
||||
// If no provider handles this scheme, this will return an error.
|
||||
func (p Providers) ByScheme(scheme string) (Getter, error) {
|
||||
for _, pp := range p {
|
||||
if pp.Provides(scheme) {
|
||||
return pp.New()
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("scheme %q not supported", scheme)
|
||||
}
|
||||
|
||||
var httpProvider = Provider{
|
||||
Schemes: []string{"http", "https"},
|
||||
New: NewHTTPGetter,
|
||||
}
|
||||
|
||||
// All finds all of the registered getters as a list of Provider instances.
|
||||
// Currently, the built-in getters and the discovered plugins with downloader
|
||||
// notations are collected.
|
||||
func All(settings *cli.EnvSettings) Providers {
|
||||
result := Providers{httpProvider}
|
||||
pluginDownloaders, _ := collectPlugins(settings)
|
||||
result = append(result, pluginDownloaders...)
|
||||
return result
|
||||
}
|
||||
126
vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go
vendored
Normal file
126
vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/internal/tlsutil"
|
||||
"helm.sh/helm/v3/internal/urlutil"
|
||||
"helm.sh/helm/v3/internal/version"
|
||||
)
|
||||
|
||||
// HTTPGetter is the default HTTP(/S) backend handler
|
||||
type HTTPGetter struct {
|
||||
opts options
|
||||
}
|
||||
|
||||
//Get performs a Get from repo.Getter and returns the body.
|
||||
func (g *HTTPGetter) Get(href string, options ...Option) (*bytes.Buffer, error) {
|
||||
for _, opt := range options {
|
||||
opt(&g.opts)
|
||||
}
|
||||
return g.get(href)
|
||||
}
|
||||
|
||||
func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Set a helm specific user agent so that a repo server and metrics can
|
||||
// separate helm calls from other tools interacting with repos.
|
||||
req, err := http.NewRequest("GET", href, nil)
|
||||
if err != nil {
|
||||
return buf, err
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", version.GetUserAgent())
|
||||
if g.opts.userAgent != "" {
|
||||
req.Header.Set("User-Agent", g.opts.userAgent)
|
||||
}
|
||||
|
||||
if g.opts.username != "" && g.opts.password != "" {
|
||||
req.SetBasicAuth(g.opts.username, g.opts.password)
|
||||
}
|
||||
|
||||
client, err := g.httpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return buf, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return buf, errors.Errorf("failed to fetch %s : %s", href, resp.Status)
|
||||
}
|
||||
|
||||
_, err = io.Copy(buf, resp.Body)
|
||||
resp.Body.Close()
|
||||
return buf, err
|
||||
}
|
||||
|
||||
// NewHTTPGetter constructs a valid http/https client as a Getter
|
||||
func NewHTTPGetter(options ...Option) (Getter, error) {
|
||||
var client HTTPGetter
|
||||
|
||||
for _, opt := range options {
|
||||
opt(&client.opts)
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
func (g *HTTPGetter) httpClient() (*http.Client, error) {
|
||||
transport := &http.Transport{
|
||||
DisableCompression: true,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" {
|
||||
tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't create TLS config for client")
|
||||
}
|
||||
tlsConf.BuildNameToCertificate()
|
||||
|
||||
sni, err := urlutil.ExtractHostname(g.opts.url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConf.ServerName = sni
|
||||
|
||||
transport.TLSClientConfig = tlsConf
|
||||
}
|
||||
|
||||
if g.opts.insecureSkipVerifyTLS {
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: g.opts.timeout,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
102
vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go
vendored
Normal file
102
vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/plugin"
|
||||
)
|
||||
|
||||
// collectPlugins scans for getter plugins.
|
||||
// This will load plugins according to the cli.
|
||||
func collectPlugins(settings *cli.EnvSettings) (Providers, error) {
|
||||
plugins, err := plugin.FindPlugins(settings.PluginsDirectory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result Providers
|
||||
for _, plugin := range plugins {
|
||||
for _, downloader := range plugin.Metadata.Downloaders {
|
||||
result = append(result, Provider{
|
||||
Schemes: downloader.Protocols,
|
||||
New: NewPluginGetter(
|
||||
downloader.Command,
|
||||
settings,
|
||||
plugin.Metadata.Name,
|
||||
plugin.Dir,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// pluginGetter is a generic type to invoke custom downloaders,
|
||||
// implemented in plugins.
|
||||
type pluginGetter struct {
|
||||
command string
|
||||
settings *cli.EnvSettings
|
||||
name string
|
||||
base string
|
||||
opts options
|
||||
}
|
||||
|
||||
// Get runs downloader plugin command
|
||||
func (p *pluginGetter) Get(href string, options ...Option) (*bytes.Buffer, error) {
|
||||
for _, opt := range options {
|
||||
opt(&p.opts)
|
||||
}
|
||||
commands := strings.Split(p.command, " ")
|
||||
argv := append(commands[1:], p.opts.certFile, p.opts.keyFile, p.opts.caFile, href)
|
||||
prog := exec.Command(filepath.Join(p.base, commands[0]), argv...)
|
||||
plugin.SetupPluginEnv(p.settings, p.name, p.base)
|
||||
prog.Env = os.Environ()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
prog.Stdout = buf
|
||||
prog.Stderr = os.Stderr
|
||||
if err := prog.Run(); err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
os.Stderr.Write(eerr.Stderr)
|
||||
return nil, errors.Errorf("plugin %q exited with error", p.command)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// NewPluginGetter constructs a valid plugin getter
|
||||
func NewPluginGetter(command string, settings *cli.EnvSettings, name, base string) Constructor {
|
||||
return func(options ...Option) (Getter, error) {
|
||||
result := &pluginGetter{
|
||||
command: command,
|
||||
settings: settings,
|
||||
name: name,
|
||||
base: base,
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(&result.opts)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
44
vendor/helm.sh/helm/v3/pkg/helmpath/home.go
vendored
Normal file
44
vendor/helm.sh/helm/v3/pkg/helmpath/home.go
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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 helmpath calculates filesystem paths to Helm's configuration, cache and data.
|
||||
package helmpath
|
||||
|
||||
// This helper builds paths to Helm's configuration, cache and data paths.
|
||||
const lp = lazypath("helm")
|
||||
|
||||
// ConfigPath returns the path where Helm stores configuration.
|
||||
func ConfigPath(elem ...string) string { return lp.configPath(elem...) }
|
||||
|
||||
// CachePath returns the path where Helm stores cached objects.
|
||||
func CachePath(elem ...string) string { return lp.cachePath(elem...) }
|
||||
|
||||
// DataPath returns the path where Helm stores data.
|
||||
func DataPath(elem ...string) string { return lp.dataPath(elem...) }
|
||||
|
||||
// CacheIndexFile returns the path to an index for the given named repository.
|
||||
func CacheIndexFile(name string) string {
|
||||
if name != "" {
|
||||
name += "-"
|
||||
}
|
||||
return name + "index.yaml"
|
||||
}
|
||||
|
||||
// CacheChartsFile returns the path to a text file listing all the charts
|
||||
// within the given named repository.
|
||||
func CacheChartsFile(name string) string {
|
||||
if name != "" {
|
||||
name += "-"
|
||||
}
|
||||
return name + "charts.txt"
|
||||
}
|
||||
72
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go
vendored
Normal file
72
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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 helmpath
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"helm.sh/helm/v3/pkg/helmpath/xdg"
|
||||
)
|
||||
|
||||
const (
|
||||
// CacheHomeEnvVar is the environment variable used by Helm
|
||||
// for the cache directory. When no value is set a default is used.
|
||||
CacheHomeEnvVar = "HELM_CACHE_HOME"
|
||||
|
||||
// ConfigHomeEnvVar is the environment variable used by Helm
|
||||
// for the config directory. When no value is set a default is used.
|
||||
ConfigHomeEnvVar = "HELM_CONFIG_HOME"
|
||||
|
||||
// DataHomeEnvVar is the environment variable used by Helm
|
||||
// for the data directory. When no value is set a default is used.
|
||||
DataHomeEnvVar = "HELM_DATA_HOME"
|
||||
)
|
||||
|
||||
// lazypath is an lazy-loaded path buffer for the XDG base directory specification.
|
||||
type lazypath string
|
||||
|
||||
func (l lazypath) path(helmEnvVar, xdgEnvVar string, defaultFn func() string, elem ...string) string {
|
||||
|
||||
// There is an order to checking for a path.
|
||||
// 1. See if a Helm specific environment variable has been set.
|
||||
// 2. Check if an XDG environment variable is set
|
||||
// 3. Fall back to a default
|
||||
base := os.Getenv(helmEnvVar)
|
||||
if base != "" {
|
||||
return filepath.Join(base, filepath.Join(elem...))
|
||||
}
|
||||
base = os.Getenv(xdgEnvVar)
|
||||
if base == "" {
|
||||
base = defaultFn()
|
||||
}
|
||||
return filepath.Join(base, string(l), filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// cachePath defines the base directory relative to which user specific non-essential data files
|
||||
// should be stored.
|
||||
func (l lazypath) cachePath(elem ...string) string {
|
||||
return l.path(CacheHomeEnvVar, xdg.CacheHomeEnvVar, cacheHome, filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// configPath defines the base directory relative to which user specific configuration files should
|
||||
// be stored.
|
||||
func (l lazypath) configPath(elem ...string) string {
|
||||
return l.path(ConfigHomeEnvVar, xdg.ConfigHomeEnvVar, configHome, filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// dataPath defines the base directory relative to which user specific data files should be stored.
|
||||
func (l lazypath) dataPath(elem ...string) string {
|
||||
return l.path(DataHomeEnvVar, xdg.DataHomeEnvVar, dataHome, filepath.Join(elem...))
|
||||
}
|
||||
34
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go
vendored
Normal file
34
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package helmpath
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
func dataHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library")
|
||||
}
|
||||
|
||||
func configHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library", "Preferences")
|
||||
}
|
||||
|
||||
func cacheHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library", "Caches")
|
||||
}
|
||||
45
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go
vendored
Normal file
45
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build !windows,!darwin
|
||||
|
||||
package helmpath
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
// dataHome defines the base directory relative to which user specific data files should be stored.
|
||||
//
|
||||
// If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share is used.
|
||||
func dataHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".local", "share")
|
||||
}
|
||||
|
||||
// configHome defines the base directory relative to which user specific configuration files should
|
||||
// be stored.
|
||||
//
|
||||
// If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config is used.
|
||||
func configHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".config")
|
||||
}
|
||||
|
||||
// cacheHome defines the base directory relative to which user specific non-essential data files
|
||||
// should be stored.
|
||||
//
|
||||
// If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache is used.
|
||||
func cacheHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".cache")
|
||||
}
|
||||
24
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go
vendored
Normal file
24
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package helmpath
|
||||
|
||||
import "os"
|
||||
|
||||
func dataHome() string { return configHome() }
|
||||
|
||||
func configHome() string { return os.Getenv("APPDATA") }
|
||||
|
||||
func cacheHome() string { return os.Getenv("TEMP") }
|
||||
34
vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go
vendored
Normal file
34
vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 xdg holds constants pertaining to XDG Base Directory Specification.
|
||||
//
|
||||
// The XDG Base Directory Specification https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
// specifies the environment variables that define user-specific base directories for various categories of files.
|
||||
package xdg
|
||||
|
||||
const (
|
||||
// CacheHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the cache directory.
|
||||
CacheHomeEnvVar = "XDG_CACHE_HOME"
|
||||
|
||||
// ConfigHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the config directory.
|
||||
ConfigHomeEnvVar = "XDG_CONFIG_HOME"
|
||||
|
||||
// DataHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the data directory.
|
||||
DataHomeEnvVar = "XDG_DATA_HOME"
|
||||
)
|
||||
29
vendor/helm.sh/helm/v3/pkg/plugin/hooks.go
vendored
Normal file
29
vendor/helm.sh/helm/v3/pkg/plugin/hooks.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 plugin // import "helm.sh/helm/v3/pkg/plugin"
|
||||
|
||||
// Types of hooks
|
||||
const (
|
||||
// Install is executed after the plugin is added.
|
||||
Install = "install"
|
||||
// Delete is executed after the plugin is removed.
|
||||
Delete = "delete"
|
||||
// Update is executed after the plugin is updated.
|
||||
Update = "update"
|
||||
)
|
||||
|
||||
// Hooks is a map of events to commands.
|
||||
type Hooks map[string]string
|
||||
225
vendor/helm.sh/helm/v3/pkg/plugin/plugin.go
vendored
Normal file
225
vendor/helm.sh/helm/v3/pkg/plugin/plugin.go
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 plugin // import "helm.sh/helm/v3/pkg/plugin"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
)
|
||||
|
||||
const PluginFileName = "plugin.yaml"
|
||||
|
||||
// Downloaders represents the plugins capability if it can retrieve
|
||||
// charts from special sources
|
||||
type Downloaders struct {
|
||||
// Protocols are the list of schemes from the charts URL.
|
||||
Protocols []string `json:"protocols"`
|
||||
// Command is the executable path with which the plugin performs
|
||||
// the actual download for the corresponding Protocols
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
// PlatformCommand represents a command for a particular operating system and architecture
|
||||
type PlatformCommand struct {
|
||||
OperatingSystem string `json:"os"`
|
||||
Architecture string `json:"arch"`
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
// Metadata describes a plugin.
|
||||
//
|
||||
// This is the plugin equivalent of a chart.Metadata.
|
||||
type Metadata struct {
|
||||
// Name is the name of the plugin
|
||||
Name string `json:"name"`
|
||||
|
||||
// Version is a SemVer 2 version of the plugin.
|
||||
Version string `json:"version"`
|
||||
|
||||
// Usage is the single-line usage text shown in help
|
||||
Usage string `json:"usage"`
|
||||
|
||||
// Description is a long description shown in places like `helm help`
|
||||
Description string `json:"description"`
|
||||
|
||||
// Command is the command, as a single string.
|
||||
//
|
||||
// The command will be passed through environment expansion, so env vars can
|
||||
// be present in this command. Unless IgnoreFlags is set, this will
|
||||
// also merge the flags passed from Helm.
|
||||
//
|
||||
// Note that command is not executed in a shell. To do so, we suggest
|
||||
// pointing the command to a shell script.
|
||||
//
|
||||
// The following rules will apply to processing commands:
|
||||
// - If platformCommand is present, it will be searched first
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be executed
|
||||
// - If OS matches and there is no more specific match, the command will be executed
|
||||
// - If no OS/Arch match is found, the default command will be executed
|
||||
// - If no command is present and no matches are found in platformCommand, Helm will exit with an error
|
||||
PlatformCommand []PlatformCommand `json:"platformCommand"`
|
||||
Command string `json:"command"`
|
||||
|
||||
// IgnoreFlags ignores any flags passed in from Helm
|
||||
//
|
||||
// For example, if the plugin is invoked as `helm --debug myplugin`, if this
|
||||
// is false, `--debug` will be appended to `--command`. If this is true,
|
||||
// the `--debug` flag will be discarded.
|
||||
IgnoreFlags bool `json:"ignoreFlags"`
|
||||
|
||||
// Hooks are commands that will run on events.
|
||||
Hooks Hooks
|
||||
|
||||
// Downloaders field is used if the plugin supply downloader mechanism
|
||||
// for special protocols.
|
||||
Downloaders []Downloaders `json:"downloaders"`
|
||||
}
|
||||
|
||||
// Plugin represents a plugin.
|
||||
type Plugin struct {
|
||||
// Metadata is a parsed representation of a plugin.yaml
|
||||
Metadata *Metadata
|
||||
// Dir is the string path to the directory that holds the plugin.
|
||||
Dir string
|
||||
}
|
||||
|
||||
// The following rules will apply to processing the Plugin.PlatformCommand.Command:
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution
|
||||
// - If OS matches and there is no more specific match, the command will be prepared for execution
|
||||
// - If no OS/Arch match is found, return nil
|
||||
func getPlatformCommand(cmds []PlatformCommand) []string {
|
||||
var command []string
|
||||
eq := strings.EqualFold
|
||||
for _, c := range cmds {
|
||||
if eq(c.OperatingSystem, runtime.GOOS) {
|
||||
command = strings.Split(os.ExpandEnv(c.Command), " ")
|
||||
}
|
||||
if eq(c.OperatingSystem, runtime.GOOS) && eq(c.Architecture, runtime.GOARCH) {
|
||||
return strings.Split(os.ExpandEnv(c.Command), " ")
|
||||
}
|
||||
}
|
||||
return command
|
||||
}
|
||||
|
||||
// PrepareCommand takes a Plugin.PlatformCommand.Command, a Plugin.Command and will applying the following processing:
|
||||
// - If platformCommand is present, it will be searched first
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution
|
||||
// - If OS matches and there is no more specific match, the command will be prepared for execution
|
||||
// - If no OS/Arch match is found, the default command will be prepared for execution
|
||||
// - If no command is present and no matches are found in platformCommand, will exit with an error
|
||||
//
|
||||
// It merges extraArgs into any arguments supplied in the plugin. It
|
||||
// returns the name of the command and an args array.
|
||||
//
|
||||
// The result is suitable to pass to exec.Command.
|
||||
func (p *Plugin) PrepareCommand(extraArgs []string) (string, []string, error) {
|
||||
var parts []string
|
||||
platCmdLen := len(p.Metadata.PlatformCommand)
|
||||
if platCmdLen > 0 {
|
||||
parts = getPlatformCommand(p.Metadata.PlatformCommand)
|
||||
}
|
||||
if platCmdLen == 0 || parts == nil {
|
||||
parts = strings.Split(os.ExpandEnv(p.Metadata.Command), " ")
|
||||
}
|
||||
if len(parts) == 0 || parts[0] == "" {
|
||||
return "", nil, fmt.Errorf("No plugin command is applicable")
|
||||
}
|
||||
|
||||
main := parts[0]
|
||||
baseArgs := []string{}
|
||||
if len(parts) > 1 {
|
||||
baseArgs = parts[1:]
|
||||
}
|
||||
if !p.Metadata.IgnoreFlags {
|
||||
baseArgs = append(baseArgs, extraArgs...)
|
||||
}
|
||||
return main, baseArgs, nil
|
||||
}
|
||||
|
||||
// LoadDir loads a plugin from the given directory.
|
||||
func LoadDir(dirname string) (*Plugin, error) {
|
||||
data, err := ioutil.ReadFile(filepath.Join(dirname, PluginFileName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plug := &Plugin{Dir: dirname}
|
||||
if err := yaml.Unmarshal(data, &plug.Metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plug, nil
|
||||
}
|
||||
|
||||
// LoadAll loads all plugins found beneath the base directory.
|
||||
//
|
||||
// This scans only one directory level.
|
||||
func LoadAll(basedir string) ([]*Plugin, error) {
|
||||
plugins := []*Plugin{}
|
||||
// We want basedir/*/plugin.yaml
|
||||
scanpath := filepath.Join(basedir, "*", PluginFileName)
|
||||
matches, err := filepath.Glob(scanpath)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
}
|
||||
|
||||
if matches == nil {
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
for _, yaml := range matches {
|
||||
dir := filepath.Dir(yaml)
|
||||
p, err := LoadDir(dir)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
}
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// FindPlugins returns a list of YAML files that describe plugins.
|
||||
func FindPlugins(plugdirs string) ([]*Plugin, error) {
|
||||
found := []*Plugin{}
|
||||
// Let's get all UNIXy and allow path separators
|
||||
for _, p := range filepath.SplitList(plugdirs) {
|
||||
matches, err := LoadAll(p)
|
||||
if err != nil {
|
||||
return matches, err
|
||||
}
|
||||
found = append(found, matches...)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// SetupPluginEnv prepares os.Env for plugins. It operates on os.Env because
|
||||
// the plugin subsystem itself needs access to the environment variables
|
||||
// created here.
|
||||
func SetupPluginEnv(settings *cli.EnvSettings, name, base string) {
|
||||
env := settings.EnvVars()
|
||||
env["HELM_PLUGIN_NAME"] = name
|
||||
env["HELM_PLUGIN_DIR"] = base
|
||||
for key, val := range env {
|
||||
os.Setenv(key, val)
|
||||
}
|
||||
}
|
||||
37
vendor/helm.sh/helm/v3/pkg/provenance/doc.go
vendored
Normal file
37
vendor/helm.sh/helm/v3/pkg/provenance/doc.go
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 provenance provides tools for establishing the authenticity of a chart.
|
||||
|
||||
In Helm, provenance is established via several factors. The primary factor is the
|
||||
cryptographic signature of a chart. Chart authors may sign charts, which in turn
|
||||
provide the necessary metadata to ensure the integrity of the chart file, the
|
||||
Chart.yaml, and the referenced Docker images.
|
||||
|
||||
A provenance file is clear-signed. This provides cryptographic verification that
|
||||
a particular block of information (Chart.yaml, archive file, images) have not
|
||||
been tampered with or altered. To learn more, read the GnuPG documentation on
|
||||
clear signatures:
|
||||
https://www.gnupg.org/gph/en/manual/x135.html
|
||||
|
||||
The cryptography used by Helm should be compatible with OpenGPG. For example,
|
||||
you should be able to verify a signature by importing the desired public key
|
||||
and using `gpg --verify`, `keybase pgp verify`, or similar:
|
||||
|
||||
$ gpg --verify some.sig
|
||||
gpg: Signature made Mon Jul 25 17:23:44 2016 MDT using RSA key ID 1FC18762
|
||||
gpg: Good signature from "Helm Testing (This key should only be used for testing. DO NOT TRUST.) <helm-testing@helm.sh>" [ultimate]
|
||||
*/
|
||||
package provenance // import "helm.sh/helm/v3/pkg/provenance"
|
||||
409
vendor/helm.sh/helm/v3/pkg/provenance/sign.go
vendored
Normal file
409
vendor/helm.sh/helm/v3/pkg/provenance/sign.go
vendored
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 provenance
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/clearsign"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
hapi "helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
)
|
||||
|
||||
var defaultPGPConfig = packet.Config{
|
||||
DefaultHash: crypto.SHA512,
|
||||
}
|
||||
|
||||
// SumCollection represents a collection of file and image checksums.
|
||||
//
|
||||
// Files are of the form:
|
||||
// FILENAME: "sha256:SUM"
|
||||
// Images are of the form:
|
||||
// "IMAGE:TAG": "sha256:SUM"
|
||||
// Docker optionally supports sha512, and if this is the case, the hash marker
|
||||
// will be 'sha512' instead of 'sha256'.
|
||||
type SumCollection struct {
|
||||
Files map[string]string `json:"files"`
|
||||
Images map[string]string `json:"images,omitempty"`
|
||||
}
|
||||
|
||||
// Verification contains information about a verification operation.
|
||||
type Verification struct {
|
||||
// SignedBy contains the entity that signed a chart.
|
||||
SignedBy *openpgp.Entity
|
||||
// FileHash is the hash, prepended with the scheme, for the file that was verified.
|
||||
FileHash string
|
||||
// FileName is the name of the file that FileHash verifies.
|
||||
FileName string
|
||||
}
|
||||
|
||||
// Signatory signs things.
|
||||
//
|
||||
// Signatories can be constructed from a PGP private key file using NewFromFiles
|
||||
// or they can be constructed manually by setting the Entity to a valid
|
||||
// PGP entity.
|
||||
//
|
||||
// The same Signatory can be used to sign or validate multiple charts.
|
||||
type Signatory struct {
|
||||
// The signatory for this instance of Helm. This is used for signing.
|
||||
Entity *openpgp.Entity
|
||||
// The keyring for this instance of Helm. This is used for verification.
|
||||
KeyRing openpgp.EntityList
|
||||
}
|
||||
|
||||
// NewFromFiles constructs a new Signatory from the PGP key in the given filename.
|
||||
//
|
||||
// This will emit an error if it cannot find a valid GPG keyfile (entity) at the
|
||||
// given location.
|
||||
//
|
||||
// Note that the keyfile may have just a public key, just a private key, or
|
||||
// both. The Signatory methods may have different requirements of the keys. For
|
||||
// example, ClearSign must have a valid `openpgp.Entity.PrivateKey` before it
|
||||
// can sign something.
|
||||
func NewFromFiles(keyfile, keyringfile string) (*Signatory, error) {
|
||||
e, err := loadKey(keyfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ring, err := loadKeyRing(keyringfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Signatory{
|
||||
Entity: e,
|
||||
KeyRing: ring,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewFromKeyring reads a keyring file and creates a Signatory.
|
||||
//
|
||||
// If id is not the empty string, this will also try to find an Entity in the
|
||||
// keyring whose name matches, and set that as the signing entity. It will return
|
||||
// an error if the id is not empty and also not found.
|
||||
func NewFromKeyring(keyringfile, id string) (*Signatory, error) {
|
||||
ring, err := loadKeyRing(keyringfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Signatory{KeyRing: ring}
|
||||
|
||||
// If the ID is empty, we can return now.
|
||||
if id == "" {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// We're gonna go all GnuPG on this and look for a string that _contains_. If
|
||||
// two or more keys contain the string and none are a direct match, we error
|
||||
// out.
|
||||
var candidate *openpgp.Entity
|
||||
vague := false
|
||||
for _, e := range ring {
|
||||
for n := range e.Identities {
|
||||
if n == id {
|
||||
s.Entity = e
|
||||
return s, nil
|
||||
}
|
||||
if strings.Contains(n, id) {
|
||||
if candidate != nil {
|
||||
vague = true
|
||||
}
|
||||
candidate = e
|
||||
}
|
||||
}
|
||||
}
|
||||
if vague {
|
||||
return s, errors.Errorf("more than one key contain the id %q", id)
|
||||
}
|
||||
|
||||
s.Entity = candidate
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// PassphraseFetcher returns a passphrase for decrypting keys.
|
||||
//
|
||||
// This is used as a callback to read a passphrase from some other location. The
|
||||
// given name is the Name field on the key, typically of the form:
|
||||
//
|
||||
// USER_NAME (COMMENT) <EMAIL>
|
||||
type PassphraseFetcher func(name string) ([]byte, error)
|
||||
|
||||
// DecryptKey decrypts a private key in the Signatory.
|
||||
//
|
||||
// If the key is not encrypted, this will return without error.
|
||||
//
|
||||
// If the key does not exist, this will return an error.
|
||||
//
|
||||
// If the key exists, but cannot be unlocked with the passphrase returned by
|
||||
// the PassphraseFetcher, this will return an error.
|
||||
//
|
||||
// If the key is successfully unlocked, it will return nil.
|
||||
func (s *Signatory) DecryptKey(fn PassphraseFetcher) error {
|
||||
if s.Entity == nil {
|
||||
return errors.New("private key not found")
|
||||
} else if s.Entity.PrivateKey == nil {
|
||||
return errors.New("provided key is not a private key. Try providing a keyring with secret keys")
|
||||
}
|
||||
|
||||
// Nothing else to do if key is not encrypted.
|
||||
if !s.Entity.PrivateKey.Encrypted {
|
||||
return nil
|
||||
}
|
||||
|
||||
fname := "Unknown"
|
||||
for i := range s.Entity.Identities {
|
||||
if i != "" {
|
||||
fname = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
p, err := fn(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Entity.PrivateKey.Decrypt(p)
|
||||
}
|
||||
|
||||
// ClearSign signs a chart with the given key.
|
||||
//
|
||||
// This takes the path to a chart archive file and a key, and it returns a clear signature.
|
||||
//
|
||||
// The Signatory must have a valid Entity.PrivateKey for this to work. If it does
|
||||
// not, an error will be returned.
|
||||
func (s *Signatory) ClearSign(chartpath string) (string, error) {
|
||||
if s.Entity == nil {
|
||||
return "", errors.New("private key not found")
|
||||
} else if s.Entity.PrivateKey == nil {
|
||||
return "", errors.New("provided key is not a private key. Try providing a keyring with secret keys")
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(chartpath); err != nil {
|
||||
return "", err
|
||||
} else if fi.IsDir() {
|
||||
return "", errors.New("cannot sign a directory")
|
||||
}
|
||||
|
||||
out := bytes.NewBuffer(nil)
|
||||
|
||||
b, err := messageBlock(chartpath)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Sign the buffer
|
||||
w, err := clearsign.Encode(out, s.Entity.PrivateKey, &defaultPGPConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = io.Copy(w, b)
|
||||
w.Close()
|
||||
return out.String(), err
|
||||
}
|
||||
|
||||
// Verify checks a signature and verifies that it is legit for a chart.
|
||||
func (s *Signatory) Verify(chartpath, sigpath string) (*Verification, error) {
|
||||
ver := &Verification{}
|
||||
for _, fname := range []string{chartpath, sigpath} {
|
||||
if fi, err := os.Stat(fname); err != nil {
|
||||
return ver, err
|
||||
} else if fi.IsDir() {
|
||||
return ver, errors.Errorf("%s cannot be a directory", fname)
|
||||
}
|
||||
}
|
||||
|
||||
// First verify the signature
|
||||
sig, err := s.decodeSignature(sigpath)
|
||||
if err != nil {
|
||||
return ver, errors.Wrap(err, "failed to decode signature")
|
||||
}
|
||||
|
||||
by, err := s.verifySignature(sig)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
ver.SignedBy = by
|
||||
|
||||
// Second, verify the hash of the tarball.
|
||||
sum, err := DigestFile(chartpath)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
_, sums, err := parseMessageBlock(sig.Plaintext)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
|
||||
sum = "sha256:" + sum
|
||||
basename := filepath.Base(chartpath)
|
||||
if sha, ok := sums.Files[basename]; !ok {
|
||||
return ver, errors.Errorf("provenance does not contain a SHA for a file named %q", basename)
|
||||
} else if sha != sum {
|
||||
return ver, errors.Errorf("sha256 sum does not match for %s: %q != %q", basename, sha, sum)
|
||||
}
|
||||
ver.FileHash = sum
|
||||
ver.FileName = basename
|
||||
|
||||
// TODO: when image signing is added, verify that here.
|
||||
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
func (s *Signatory) decodeSignature(filename string) (*clearsign.Block, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := clearsign.Decode(data)
|
||||
if block == nil {
|
||||
// There was no sig in the file.
|
||||
return nil, errors.New("signature block not found")
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// verifySignature verifies that the given block is validly signed, and returns the signer.
|
||||
func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) {
|
||||
return openpgp.CheckDetachedSignature(
|
||||
s.KeyRing,
|
||||
bytes.NewBuffer(block.Bytes),
|
||||
block.ArmoredSignature.Body,
|
||||
)
|
||||
}
|
||||
|
||||
func messageBlock(chartpath string) (*bytes.Buffer, error) {
|
||||
var b *bytes.Buffer
|
||||
// Checksum the archive
|
||||
chash, err := DigestFile(chartpath)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
base := filepath.Base(chartpath)
|
||||
sums := &SumCollection{
|
||||
Files: map[string]string{
|
||||
base: "sha256:" + chash,
|
||||
},
|
||||
}
|
||||
|
||||
// Load the archive into memory.
|
||||
chart, err := loader.LoadFile(chartpath)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
// Buffer a hash + checksums YAML file
|
||||
data, err := yaml.Marshal(chart.Metadata)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
// FIXME: YAML uses ---\n as a file start indicator, but this is not legal in a PGP
|
||||
// clearsign block. So we use ...\n, which is the YAML document end marker.
|
||||
// http://yaml.org/spec/1.2/spec.html#id2800168
|
||||
b = bytes.NewBuffer(data)
|
||||
b.WriteString("\n...\n")
|
||||
|
||||
data, err = yaml.Marshal(sums)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
b.Write(data)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseMessageBlock
|
||||
func parseMessageBlock(data []byte) (*hapi.Metadata, *SumCollection, error) {
|
||||
// This sucks.
|
||||
parts := bytes.Split(data, []byte("\n...\n"))
|
||||
if len(parts) < 2 {
|
||||
return nil, nil, errors.New("message block must have at least two parts")
|
||||
}
|
||||
|
||||
md := &hapi.Metadata{}
|
||||
sc := &SumCollection{}
|
||||
|
||||
if err := yaml.Unmarshal(parts[0], md); err != nil {
|
||||
return md, sc, err
|
||||
}
|
||||
err := yaml.Unmarshal(parts[1], sc)
|
||||
return md, sc, err
|
||||
}
|
||||
|
||||
// loadKey loads a GPG key found at a particular path.
|
||||
func loadKey(keypath string) (*openpgp.Entity, error) {
|
||||
f, err := os.Open(keypath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
pr := packet.NewReader(f)
|
||||
return openpgp.ReadEntity(pr)
|
||||
}
|
||||
|
||||
func loadKeyRing(ringpath string) (openpgp.EntityList, error) {
|
||||
f, err := os.Open(ringpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return openpgp.ReadKeyRing(f)
|
||||
}
|
||||
|
||||
// DigestFile calculates a SHA256 hash (like Docker) for a given file.
|
||||
//
|
||||
// It takes the path to the archive file, and returns a string representation of
|
||||
// the SHA256 sum.
|
||||
//
|
||||
// The intended use of this function is to generate a sum of a chart TGZ file.
|
||||
func DigestFile(filename string) (string, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return Digest(f)
|
||||
}
|
||||
|
||||
// Digest hashes a reader and returns a SHA256 digest.
|
||||
//
|
||||
// Helm uses SHA256 as its default hash for all non-cryptographic applications.
|
||||
func Digest(in io.Reader) (string, error) {
|
||||
hash := crypto.SHA256.New()
|
||||
if _, err := io.Copy(hash, in); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
285
vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go
vendored
Normal file
285
vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 "helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/helmpath"
|
||||
"helm.sh/helm/v3/pkg/provenance"
|
||||
)
|
||||
|
||||
// Entry represents a collection of parameters for chart repository
|
||||
type Entry struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
CAFile string `json:"caFile"`
|
||||
InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"`
|
||||
}
|
||||
|
||||
// ChartRepository represents a chart repository
|
||||
type ChartRepository struct {
|
||||
Config *Entry
|
||||
ChartPaths []string
|
||||
IndexFile *IndexFile
|
||||
Client getter.Getter
|
||||
CachePath string
|
||||
}
|
||||
|
||||
// NewChartRepository constructs ChartRepository
|
||||
func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
|
||||
u, err := url.Parse(cfg.URL)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid chart URL format: %s", cfg.URL)
|
||||
}
|
||||
|
||||
client, err := getters.ByScheme(u.Scheme)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("could not find protocol handler for: %s", u.Scheme)
|
||||
}
|
||||
|
||||
return &ChartRepository{
|
||||
Config: cfg,
|
||||
IndexFile: NewIndexFile(),
|
||||
Client: client,
|
||||
CachePath: helmpath.CachePath("repository"),
|
||||
}, 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 errors.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 := LoadIndexFile(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() (string, error) {
|
||||
parsedURL, err := url.Parse(r.Config.URL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
parsedURL.RawPath = path.Join(parsedURL.RawPath, "index.yaml")
|
||||
parsedURL.Path = path.Join(parsedURL.Path, "index.yaml")
|
||||
|
||||
indexURL := parsedURL.String()
|
||||
// TODO add user-agent
|
||||
resp, err := r.Client.Get(indexURL,
|
||||
getter.WithURL(r.Config.URL),
|
||||
getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify),
|
||||
getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile),
|
||||
getter.WithBasicAuth(r.Config.Username, r.Config.Password),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
index, err := ioutil.ReadAll(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
indexFile, err := loadIndex(index)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create the chart list file in the cache directory
|
||||
var charts strings.Builder
|
||||
for name := range indexFile.Entries {
|
||||
fmt.Fprintln(&charts, name)
|
||||
}
|
||||
chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
|
||||
os.MkdirAll(filepath.Dir(chartsFile), 0755)
|
||||
ioutil.WriteFile(chartsFile, []byte(charts.String()), 0644)
|
||||
|
||||
// Create the index file in the cache directory
|
||||
fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name))
|
||||
os.MkdirAll(filepath.Dir(fname), 0755)
|
||||
return fname, ioutil.WriteFile(fname, 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 := loader.Load(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
digest, err := provenance.DigestFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.IndexFile.Has(ch.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
|
||||
}
|
||||
|
||||
// FindChartInRepoURL finds chart in chart repository pointed by repoURL
|
||||
// without adding repo to repositories
|
||||
func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
|
||||
return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters)
|
||||
}
|
||||
|
||||
// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL
|
||||
// without adding repo to repositories, like FindChartInRepoURL,
|
||||
// but it also receives credentials for the chart repository.
|
||||
func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
|
||||
|
||||
// Download and write the index file to a temporary location
|
||||
buf := make([]byte, 20)
|
||||
rand.Read(buf)
|
||||
name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-")
|
||||
|
||||
c := Entry{
|
||||
URL: repoURL,
|
||||
Username: username,
|
||||
Password: password,
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
CAFile: caFile,
|
||||
Name: name,
|
||||
}
|
||||
r, err := NewChartRepository(&c, getters)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
idx, err := r.DownloadIndexFile()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL)
|
||||
}
|
||||
|
||||
// Read the index file for the repository to get chart information and return chart URL
|
||||
repoIndex, err := LoadIndexFile(idx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
errMsg := fmt.Sprintf("chart %q", chartName)
|
||||
if chartVersion != "" {
|
||||
errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion)
|
||||
}
|
||||
cv, err := repoIndex.Get(chartName, chartVersion)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL)
|
||||
}
|
||||
|
||||
if len(cv.URLs) == 0 {
|
||||
return "", errors.Errorf("%s has no downloadable URLs", errMsg)
|
||||
}
|
||||
|
||||
chartURL := cv.URLs[0]
|
||||
|
||||
absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to make chart URL absolute")
|
||||
}
|
||||
|
||||
return absoluteChartURL, nil
|
||||
}
|
||||
|
||||
// ResolveReferenceURL resolves refURL relative to baseURL.
|
||||
// If refURL is absolute, it simply returns refURL.
|
||||
func ResolveReferenceURL(baseURL, refURL string) (string, error) {
|
||||
parsedBaseURL, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL)
|
||||
}
|
||||
|
||||
parsedRefURL, err := url.Parse(refURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to parse %s as URL", refURL)
|
||||
}
|
||||
|
||||
// We need a trailing slash for ResolveReference to work, but make sure there isn't already one
|
||||
parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/"
|
||||
return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil
|
||||
}
|
||||
|
||||
func (e *Entry) String() string {
|
||||
buf, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
93
vendor/helm.sh/helm/v3/pkg/repo/doc.go
vendored
Normal file
93
vendor/helm.sh/helm/v3/pkg/repo/doc.go
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 implements the Helm Chart Repository.
|
||||
|
||||
A chart repository is an HTTP server that provides information on charts. A local
|
||||
repository cache is an on-disk representation of a chart repository.
|
||||
|
||||
There are two important file formats for chart repositories.
|
||||
|
||||
The first is the 'index.yaml' format, which is expressed like this:
|
||||
|
||||
apiVersion: v1
|
||||
entries:
|
||||
frobnitz:
|
||||
- created: 2016-09-29T12:14:34.830161306-06:00
|
||||
description: This is a frobnitz.
|
||||
digest: 587bd19a9bd9d2bc4a6d25ab91c8c8e7042c47b4ac246e37bf8e1e74386190f4
|
||||
home: http://example.com
|
||||
keywords:
|
||||
- frobnitz
|
||||
- sprocket
|
||||
- dodad
|
||||
maintainers:
|
||||
- email: helm@example.com
|
||||
name: The Helm Team
|
||||
- email: nobody@example.com
|
||||
name: Someone Else
|
||||
name: frobnitz
|
||||
urls:
|
||||
- http://example-charts.com/testdata/repository/frobnitz-1.2.3.tgz
|
||||
version: 1.2.3
|
||||
sprocket:
|
||||
- created: 2016-09-29T12:14:34.830507606-06:00
|
||||
description: This is a sprocket"
|
||||
digest: 8505ff813c39502cc849a38e1e4a8ac24b8e6e1dcea88f4c34ad9b7439685ae6
|
||||
home: http://example.com
|
||||
keywords:
|
||||
- frobnitz
|
||||
- sprocket
|
||||
- dodad
|
||||
maintainers:
|
||||
- email: helm@example.com
|
||||
name: The Helm Team
|
||||
- email: nobody@example.com
|
||||
name: Someone Else
|
||||
name: sprocket
|
||||
urls:
|
||||
- http://example-charts.com/testdata/repository/sprocket-1.2.0.tgz
|
||||
version: 1.2.0
|
||||
generated: 2016-09-29T12:14:34.829721375-06:00
|
||||
|
||||
An index.yaml file contains the necessary descriptive information about what
|
||||
charts are available in a repository, and how to get them.
|
||||
|
||||
The second file format is the repositories.yaml file format. This file is for
|
||||
facilitating local cached copies of one or more chart repositories.
|
||||
|
||||
The format of a repository.yaml file is:
|
||||
|
||||
apiVersion: v1
|
||||
generated: TIMESTAMP
|
||||
repositories:
|
||||
- name: stable
|
||||
url: http://example.com/charts
|
||||
cache: stable-index.yaml
|
||||
- name: incubator
|
||||
url: http://example.com/incubator
|
||||
cache: incubator-index.yaml
|
||||
|
||||
This file maps three bits of information about a repository:
|
||||
|
||||
- The name the user uses to refer to it
|
||||
- The fully qualified URL to the repository (index.yaml will be appended)
|
||||
- The name of the local cachefile
|
||||
|
||||
The format for both files was changed after Helm v2.0.0-Alpha.4. Helm is not
|
||||
backwards compatible with those earlier versions.
|
||||
*/
|
||||
package repo
|
||||
292
vendor/helm.sh/helm/v3/pkg/repo/index.go
vendored
Normal file
292
vendor/helm.sh/helm/v3/pkg/repo/index.go
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/internal/fileutil"
|
||||
"helm.sh/helm/v3/internal/urlutil"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/provenance"
|
||||
)
|
||||
|
||||
var indexPath = "index.yaml"
|
||||
|
||||
// APIVersionV1 is the v1 API version for index and repository files.
|
||||
const APIVersionV1 = "v1"
|
||||
|
||||
var (
|
||||
// ErrNoAPIVersion indicates that an API version was not specified.
|
||||
ErrNoAPIVersion = errors.New("no API version specified")
|
||||
// ErrNoChartVersion indicates that a chart with the given version is not found.
|
||||
ErrNoChartVersion = errors.New("no chart version found")
|
||||
// ErrNoChartName indicates that a chart with the given name is not found.
|
||||
ErrNoChartName = errors.New("no chart name found")
|
||||
)
|
||||
|
||||
// ChartVersions is a list of versioned chart references.
|
||||
// Implements a sorter on Version.
|
||||
type ChartVersions []*ChartVersion
|
||||
|
||||
// Len returns the length.
|
||||
func (c ChartVersions) Len() int { return len(c) }
|
||||
|
||||
// Swap swaps the position of two items in the versions slice.
|
||||
func (c ChartVersions) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
|
||||
// Less returns true if the version of entry a is less than the version of entry b.
|
||||
func (c ChartVersions) Less(a, b int) bool {
|
||||
// Failed parse pushes to the back.
|
||||
i, err := semver.NewVersion(c[a].Version)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
j, err := semver.NewVersion(c[b].Version)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return i.LessThan(j)
|
||||
}
|
||||
|
||||
// IndexFile represents the index file in a chart repository
|
||||
type IndexFile struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Entries map[string]ChartVersions `json:"entries"`
|
||||
PublicKeys []string `json:"publicKeys,omitempty"`
|
||||
}
|
||||
|
||||
// NewIndexFile initializes an index.
|
||||
func NewIndexFile() *IndexFile {
|
||||
return &IndexFile{
|
||||
APIVersion: APIVersionV1,
|
||||
Generated: time.Now(),
|
||||
Entries: map[string]ChartVersions{},
|
||||
PublicKeys: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadIndexFile takes a file at the given path and returns an IndexFile object
|
||||
func LoadIndexFile(path string) (*IndexFile, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return loadIndex(b)
|
||||
}
|
||||
|
||||
// Add adds a file to the index
|
||||
// This can leave the index in an unsorted state
|
||||
func (i IndexFile) Add(md *chart.Metadata, filename, baseURL, digest string) {
|
||||
u := filename
|
||||
if baseURL != "" {
|
||||
var err error
|
||||
_, file := filepath.Split(filename)
|
||||
u, err = urlutil.URLJoin(baseURL, file)
|
||||
if err != nil {
|
||||
u = path.Join(baseURL, file)
|
||||
}
|
||||
}
|
||||
cr := &ChartVersion{
|
||||
URLs: []string{u},
|
||||
Metadata: md,
|
||||
Digest: digest,
|
||||
Created: time.Now(),
|
||||
}
|
||||
if ee, ok := i.Entries[md.Name]; !ok {
|
||||
i.Entries[md.Name] = ChartVersions{cr}
|
||||
} else {
|
||||
i.Entries[md.Name] = append(ee, cr)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if the index has an entry for a chart with the given name and exact version.
|
||||
func (i IndexFile) Has(name, version string) bool {
|
||||
_, err := i.Get(name, version)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// SortEntries sorts the entries by version in descending order.
|
||||
//
|
||||
// In canonical form, the individual version records should be sorted so that
|
||||
// the most recent release for every version is in the 0th slot in the
|
||||
// Entries.ChartVersions array. That way, tooling can predict the newest
|
||||
// version without needing to parse SemVers.
|
||||
func (i IndexFile) SortEntries() {
|
||||
for _, versions := range i.Entries {
|
||||
sort.Sort(sort.Reverse(versions))
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the ChartVersion for the given name.
|
||||
//
|
||||
// If version is empty, this will return the chart with the latest stable version,
|
||||
// prerelease versions will be skipped.
|
||||
func (i IndexFile) Get(name, version string) (*ChartVersion, error) {
|
||||
vs, ok := i.Entries[name]
|
||||
if !ok {
|
||||
return nil, ErrNoChartName
|
||||
}
|
||||
if len(vs) == 0 {
|
||||
return nil, ErrNoChartVersion
|
||||
}
|
||||
|
||||
var constraint *semver.Constraints
|
||||
if version == "" {
|
||||
constraint, _ = semver.NewConstraint("*")
|
||||
} else {
|
||||
var err error
|
||||
constraint, err = semver.NewConstraint(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// when customer input exact version, check whether have exact match one first
|
||||
if len(version) != 0 {
|
||||
for _, ver := range vs {
|
||||
if version == ver.Version {
|
||||
return ver, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ver := range vs {
|
||||
test, err := semver.NewVersion(ver.Version)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if constraint.Check(test) {
|
||||
return ver, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("no chart version found for %s-%s", name, version)
|
||||
}
|
||||
|
||||
// WriteFile writes an index file to the given destination path.
|
||||
//
|
||||
// The mode on the file is set to 'mode'.
|
||||
func (i IndexFile) WriteFile(dest string, mode os.FileMode) error {
|
||||
b, err := yaml.Marshal(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode)
|
||||
}
|
||||
|
||||
// Merge merges the given index file into this index.
|
||||
//
|
||||
// This merges by name and version.
|
||||
//
|
||||
// If one of the entries in the given index does _not_ already exist, it is added.
|
||||
// In all other cases, the existing record is preserved.
|
||||
//
|
||||
// This can leave the index in an unsorted state
|
||||
func (i *IndexFile) Merge(f *IndexFile) {
|
||||
for _, cvs := range f.Entries {
|
||||
for _, cv := range cvs {
|
||||
if !i.Has(cv.Name, cv.Version) {
|
||||
e := i.Entries[cv.Name]
|
||||
i.Entries[cv.Name] = append(e, cv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChartVersion represents a chart entry in the IndexFile
|
||||
type ChartVersion struct {
|
||||
*chart.Metadata
|
||||
URLs []string `json:"urls"`
|
||||
Created time.Time `json:"created,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
Digest string `json:"digest,omitempty"`
|
||||
}
|
||||
|
||||
// IndexDirectory reads a (flat) directory and generates an index.
|
||||
//
|
||||
// It indexes only charts that have been packaged (*.tgz).
|
||||
//
|
||||
// The index returned will be in an unsorted state
|
||||
func IndexDirectory(dir, baseURL string) (*IndexFile, error) {
|
||||
archives, err := filepath.Glob(filepath.Join(dir, "*.tgz"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
moreArchives, err := filepath.Glob(filepath.Join(dir, "**/*.tgz"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
archives = append(archives, moreArchives...)
|
||||
|
||||
index := NewIndexFile()
|
||||
for _, arch := range archives {
|
||||
fname, err := filepath.Rel(dir, arch)
|
||||
if err != nil {
|
||||
return index, err
|
||||
}
|
||||
|
||||
var parentDir string
|
||||
parentDir, fname = filepath.Split(fname)
|
||||
// filepath.Split appends an extra slash to the end of parentDir. We want to strip that out.
|
||||
parentDir = strings.TrimSuffix(parentDir, string(os.PathSeparator))
|
||||
parentURL, err := urlutil.URLJoin(baseURL, parentDir)
|
||||
if err != nil {
|
||||
parentURL = path.Join(baseURL, parentDir)
|
||||
}
|
||||
|
||||
c, err := loader.Load(arch)
|
||||
if err != nil {
|
||||
// Assume this is not a chart.
|
||||
continue
|
||||
}
|
||||
hash, err := provenance.DigestFile(arch)
|
||||
if err != nil {
|
||||
return index, err
|
||||
}
|
||||
index.Add(c.Metadata, fname, parentURL, hash)
|
||||
}
|
||||
return index, nil
|
||||
}
|
||||
|
||||
// loadIndex loads an index file and does minimal validity checking.
|
||||
//
|
||||
// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails.
|
||||
func loadIndex(data []byte) (*IndexFile, error) {
|
||||
i := &IndexFile{}
|
||||
if err := yaml.Unmarshal(data, i); err != nil {
|
||||
return i, err
|
||||
}
|
||||
i.SortEntries()
|
||||
if i.APIVersion == "" {
|
||||
return i, ErrNoAPIVersion
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
123
vendor/helm.sh/helm/v3/pkg/repo/repo.go
vendored
Normal file
123
vendor/helm.sh/helm/v3/pkg/repo/repo.go
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 "helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// File represents the repositories.yaml file
|
||||
type File struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Repositories []*Entry `json:"repositories"`
|
||||
}
|
||||
|
||||
// NewFile generates an empty repositories file.
|
||||
//
|
||||
// Generated and APIVersion are automatically set.
|
||||
func NewFile() *File {
|
||||
return &File{
|
||||
APIVersion: APIVersionV1,
|
||||
Generated: time.Now(),
|
||||
Repositories: []*Entry{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFile takes a file at the given path and returns a File object
|
||||
func LoadFile(path string) (*File, error) {
|
||||
r := new(File)
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return r, errors.Wrapf(err, "couldn't load repositories file (%s)", path)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(b, r)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// Add adds one or more repo entries to a repo file.
|
||||
func (r *File) Add(re ...*Entry) {
|
||||
r.Repositories = append(r.Repositories, re...)
|
||||
}
|
||||
|
||||
// Update attempts to replace one or more repo entries in a repo file. If an
|
||||
// entry with the same name doesn't exist in the repo file it will add it.
|
||||
func (r *File) Update(re ...*Entry) {
|
||||
for _, target := range re {
|
||||
r.update(target)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *File) update(e *Entry) {
|
||||
for j, repo := range r.Repositories {
|
||||
if repo.Name == e.Name {
|
||||
r.Repositories[j] = e
|
||||
return
|
||||
}
|
||||
}
|
||||
r.Add(e)
|
||||
}
|
||||
|
||||
// Has returns true if the given name is already a repository name.
|
||||
func (r *File) Has(name string) bool {
|
||||
entry := r.Get(name)
|
||||
return entry != nil
|
||||
}
|
||||
|
||||
// Get returns an entry with the given name if it exists, otherwise returns nil
|
||||
func (r *File) Get(name string) *Entry {
|
||||
for _, entry := range r.Repositories {
|
||||
if entry.Name == name {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes the entry from the list of repositories.
|
||||
func (r *File) Remove(name string) bool {
|
||||
cp := []*Entry{}
|
||||
found := false
|
||||
for _, rf := range r.Repositories {
|
||||
if rf.Name == name {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
cp = append(cp, rf)
|
||||
}
|
||||
r.Repositories = cp
|
||||
return found
|
||||
}
|
||||
|
||||
// WriteFile writes a repositories file to the given path.
|
||||
func (r *File) WriteFile(path string, perm os.FileMode) error {
|
||||
data, err := yaml.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, perm)
|
||||
}
|
||||
Reference in New Issue
Block a user