mirror of https://github.com/kubernetes/kops.git
Use helm's merging of vaulefiles and files
This commit is contained in:
parent
b6a07c16fe
commit
24c9d03477
|
|
@ -103,6 +103,7 @@ go_library(
|
|||
"//vendor/github.com/spf13/cobra/doc:go_default_library",
|
||||
"//vendor/github.com/spf13/viper:go_default_library",
|
||||
"//vendor/golang.org/x/crypto/ssh:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/cli/values:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/strvals:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
|
|
@ -156,6 +157,7 @@ go_test(
|
|||
"//channels:channeldata", # keep
|
||||
"//tests/integration/create_cluster:exported_testdata", # keep
|
||||
"//tests/integration/update_cluster:exported_testdata", # keep
|
||||
"test/values.yaml",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
shard_count = 10,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import (
|
|||
"k8s.io/kubectl/pkg/util/templates"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
helmvalues "helm.sh/helm/v3/pkg/cli/values"
|
||||
|
||||
"k8s.io/kops/cmd/kops/util"
|
||||
kopsapi "k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/try"
|
||||
|
|
@ -250,7 +252,16 @@ func newTemplateContext(files []string, values []string, stringValues []string)
|
|||
return nil, fmt.Errorf("unable decode the configuration file: %s, error: %v", j, err)
|
||||
}
|
||||
|
||||
context = mergeValues(context, ctx)
|
||||
valueOpts := &helmvalues.Options{
|
||||
Values: values,
|
||||
ValueFiles: files,
|
||||
StringValues: stringValues,
|
||||
}
|
||||
|
||||
context, err = valueOpts.MergeValues(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271,35 +282,6 @@ func newTemplateContext(files []string, values []string, stringValues []string)
|
|||
return context, nil
|
||||
}
|
||||
|
||||
// Merges source and destination map, preferring values from the source map
|
||||
// Copied from the Helm (https://github.com/kubernetes/helm) project:
|
||||
// https://github.com/kubernetes/helm/blob/282984e75fd115a0765730efe09d8257c72fa56d/cmd/helm/install.go#L302
|
||||
func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
|
||||
for k, v := range src {
|
||||
// If the key doesn't exist already, then just set the key to that value
|
||||
if _, exists := dest[k]; !exists {
|
||||
dest[k] = v
|
||||
continue
|
||||
}
|
||||
nextMap, ok := v.(map[string]interface{})
|
||||
// If it isn't another map, overwrite the value
|
||||
if !ok {
|
||||
dest[k] = v
|
||||
continue
|
||||
}
|
||||
// Edge case: If the key exists in the destination, but isn't a map
|
||||
destMap, isMap := dest[k].(map[string]interface{})
|
||||
// If the source map has a map for this key, prefer it
|
||||
if !isMap {
|
||||
dest[k] = v
|
||||
continue
|
||||
}
|
||||
// If we got to this point, it is a map in both, so merge them
|
||||
dest[k] = mergeValues(destMap, nextMap)
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
// expandFiles is responsible for resolving any references to directories
|
||||
func expandFiles(path string) ([]string, error) {
|
||||
// @check if the path is a directory, if not we can return straight away
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
* Added [template funtions](https://kops.sigs.k8s.io/operations/cluster_template/#template-functions) for kubernetes version based on channel data.
|
||||
|
||||
* The helm functions used to parse `--set` flags on `kops toolbox template` has been updated to helm3, which has a slightly different behaviour from helm3.
|
||||
* kOps now use helm3 functions for merging template `--set` and `--values` arguments. This has slightly different behaviour than previous helm2-like logic.
|
||||
|
||||
# Breaking changes
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cfg.go",
|
||||
"tls.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/internal/tlsutil",
|
||||
importpath = "helm.sh/helm/v3/internal/tlsutil",
|
||||
visibility = ["//vendor/helm.sh/helm/v3:__subpackages__"],
|
||||
deps = ["//vendor/github.com/pkg/errors:go_default_library"],
|
||||
)
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
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 tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Options represents configurable options used to create client and server TLS configurations.
|
||||
type Options struct {
|
||||
CaCertFile string
|
||||
// If either the KeyFile or CertFile is empty, ClientConfig() will not load them.
|
||||
KeyFile string
|
||||
CertFile string
|
||||
// Client-only options
|
||||
InsecureSkipVerify bool
|
||||
}
|
||||
|
||||
// ClientConfig returns a TLS configuration for use by a Helm client.
|
||||
func ClientConfig(opts Options) (cfg *tls.Config, err error) {
|
||||
var cert *tls.Certificate
|
||||
var pool *x509.CertPool
|
||||
|
||||
if opts.CertFile != "" || opts.KeyFile != "" {
|
||||
if cert, err = CertFromFilePair(opts.CertFile, opts.KeyFile); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.Wrapf(err, "could not load x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "could not read x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
|
||||
}
|
||||
}
|
||||
if !opts.InsecureSkipVerify && opts.CaCertFile != "" {
|
||||
if pool, err = CertPoolFromFile(opts.CaCertFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool}
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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 tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// NewClientTLS returns tls.Config appropriate for client auth.
|
||||
func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) {
|
||||
config := tls.Config{}
|
||||
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := CertFromFilePair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Certificates = []tls.Certificate{*cert}
|
||||
}
|
||||
|
||||
if caFile != "" {
|
||||
cp, err := CertPoolFromFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.RootCAs = cp
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// CertPoolFromFile returns an x509.CertPool containing the certificates
|
||||
// in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not
|
||||
// be parsed, or if the file does not contain any certificates
|
||||
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("can't read CA file: %v", filename)
|
||||
}
|
||||
cp := x509.NewCertPool()
|
||||
if !cp.AppendCertsFromPEM(b) {
|
||||
return nil, errors.Errorf("failed to append certificates from file: %s", filename)
|
||||
}
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
// CertFromFilePair returns an tls.Certificate containing the
|
||||
// certificates public/private key pair from a pair of given PEM-encoded files.
|
||||
// Returns an error if the file could not be read, a certificate could not
|
||||
// be parsed, or if the file does not contain any certificates
|
||||
func CertFromFilePair(certFile, keyFile string) (*tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load key pair from cert %s and key %s", certFile, keyFile)
|
||||
}
|
||||
return &cert, err
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["urlutil.go"],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/internal/urlutil",
|
||||
importpath = "helm.sh/helm/v3/internal/urlutil",
|
||||
visibility = ["//vendor/helm.sh/helm/v3:__subpackages__"],
|
||||
)
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
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 urlutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// URLJoin joins a base URL to one or more path components.
|
||||
//
|
||||
// It's like filepath.Join for URLs. If the baseURL is pathish, this will still
|
||||
// perform a join.
|
||||
//
|
||||
// If the URL is unparsable, this returns an error.
|
||||
func URLJoin(baseURL string, paths ...string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// We want path instead of filepath because path always uses /.
|
||||
all := []string{u.Path}
|
||||
all = append(all, paths...)
|
||||
u.Path = path.Join(all...)
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// Equal normalizes two URLs and then compares for equality.
|
||||
func Equal(a, b string) bool {
|
||||
au, err := url.Parse(a)
|
||||
if err != nil {
|
||||
a = filepath.Clean(a)
|
||||
b = filepath.Clean(b)
|
||||
// If urls are paths, return true only if they are an exact match
|
||||
return a == b
|
||||
}
|
||||
bu, err := url.Parse(b)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, u := range []*url.URL{au, bu} {
|
||||
if u.Path == "" {
|
||||
u.Path = "/"
|
||||
}
|
||||
u.Path = filepath.Clean(u.Path)
|
||||
}
|
||||
return au.String() == bu.String()
|
||||
}
|
||||
|
||||
// ExtractHostname returns hostname from URL
|
||||
func ExtractHostname(addr string) (string, error) {
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u.Hostname(), nil
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["version.go"],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/internal/version",
|
||||
importpath = "helm.sh/helm/v3/internal/version",
|
||||
visibility = ["//vendor/helm.sh/helm/v3:__subpackages__"],
|
||||
)
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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 version // import "helm.sh/helm/v3/internal/version"
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// version is the current version of Helm.
|
||||
// Update this whenever making a new release.
|
||||
// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
|
||||
//
|
||||
// Increment major number for new feature additions and behavioral changes.
|
||||
// Increment minor number for bug fixes and performance enhancements.
|
||||
version = "v3.4"
|
||||
|
||||
// metadata is extra build time data
|
||||
metadata = ""
|
||||
// gitCommit is the git sha1
|
||||
gitCommit = ""
|
||||
// gitTreeState is the state of the git tree
|
||||
gitTreeState = ""
|
||||
)
|
||||
|
||||
// BuildInfo describes the compile time information.
|
||||
type BuildInfo struct {
|
||||
// Version is the current semver.
|
||||
Version string `json:"version,omitempty"`
|
||||
// GitCommit is the git sha1.
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
// GitTreeState is the state of the git tree.
|
||||
GitTreeState string `json:"git_tree_state,omitempty"`
|
||||
// GoVersion is the version of the Go compiler used.
|
||||
GoVersion string `json:"go_version,omitempty"`
|
||||
}
|
||||
|
||||
// GetVersion returns the semver string of the version
|
||||
func GetVersion() string {
|
||||
if metadata == "" {
|
||||
return version
|
||||
}
|
||||
return version + "+" + metadata
|
||||
}
|
||||
|
||||
// GetUserAgent returns a user agent for user with an HTTP client
|
||||
func GetUserAgent() string {
|
||||
return "Helm/" + strings.TrimPrefix(GetVersion(), "v")
|
||||
}
|
||||
|
||||
// Get returns build info
|
||||
func Get() BuildInfo {
|
||||
v := BuildInfo{
|
||||
Version: GetVersion(),
|
||||
GitCommit: gitCommit,
|
||||
GitTreeState: gitTreeState,
|
||||
GoVersion: runtime.Version(),
|
||||
}
|
||||
|
||||
// HACK(bacongobbler): strip out GoVersion during a test run for consistent test output
|
||||
if flag.Lookup("test.v") != nil {
|
||||
v.GoVersion = ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["environment.go"],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/cli",
|
||||
importpath = "helm.sh/helm/v3/pkg/cli",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/helmpath:go_default_library",
|
||||
"//vendor/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
|
||||
"helm.sh/helm/v3/pkg/helmpath"
|
||||
)
|
||||
|
||||
// defaultMaxHistory sets the maximum number of releases to 0: unlimited
|
||||
const defaultMaxHistory = 10
|
||||
|
||||
// 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
|
||||
// Username to impersonate for the operation
|
||||
KubeAsUser string
|
||||
// Groups to impersonate for the operation, multiple groups parsed from a comma delimited list
|
||||
KubeAsGroups []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
|
||||
// MaxHistory is the max release history maintained.
|
||||
MaxHistory int
|
||||
}
|
||||
|
||||
func New() *EnvSettings {
|
||||
env := &EnvSettings{
|
||||
namespace: os.Getenv("HELM_NAMESPACE"),
|
||||
MaxHistory: envIntOr("HELM_MAX_HISTORY", defaultMaxHistory),
|
||||
KubeContext: os.Getenv("HELM_KUBECONTEXT"),
|
||||
KubeToken: os.Getenv("HELM_KUBETOKEN"),
|
||||
KubeAsUser: os.Getenv("HELM_KUBEASUSER"),
|
||||
KubeAsGroups: envCSV("HELM_KUBEASGROUPS"),
|
||||
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,
|
||||
Impersonate: &env.KubeAsUser,
|
||||
ImpersonateGroup: &env.KubeAsGroups,
|
||||
}
|
||||
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.KubeAsUser, "kube-as-user", s.KubeAsUser, "Username to impersonate for the operation")
|
||||
fs.StringArrayVar(&s.KubeAsGroups, "kube-as-group", s.KubeAsGroups, "Group to impersonate for the operation, this flag can be repeated to specify multiple groups.")
|
||||
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 envIntOr(name string, def int) int {
|
||||
if name == "" {
|
||||
return def
|
||||
}
|
||||
envVal := envOr(name, strconv.Itoa(def))
|
||||
ret, err := strconv.Atoi(envVal)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func envCSV(name string) (ls []string) {
|
||||
trimmed := strings.Trim(os.Getenv(name), ", ")
|
||||
if trimmed != "" {
|
||||
ls = strings.Split(trimmed, ",")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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(),
|
||||
"HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory),
|
||||
|
||||
// broken, these are populated from helm flags and not kubeconfig.
|
||||
"HELM_KUBECONTEXT": s.KubeContext,
|
||||
"HELM_KUBETOKEN": s.KubeToken,
|
||||
"HELM_KUBEASUSER": s.KubeAsUser,
|
||||
"HELM_KUBEASGROUPS": strings.Join(s.KubeAsGroups, ","),
|
||||
"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
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["options.go"],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/cli/values",
|
||||
importpath = "helm.sh/helm/v3/pkg/cli/values",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/getter:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/strvals:go_default_library",
|
||||
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
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 values
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/strvals"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
ValueFiles []string
|
||||
StringValues []string
|
||||
Values []string
|
||||
FileValues []string
|
||||
}
|
||||
|
||||
// MergeValues merges values from files specified via -f/--values and directly
|
||||
// via --set, --set-string, or --set-file, marshaling them to YAML
|
||||
func (opts *Options) MergeValues(p getter.Providers) (map[string]interface{}, error) {
|
||||
base := map[string]interface{}{}
|
||||
|
||||
// User specified a values files via -f/--values
|
||||
for _, filePath := range opts.ValueFiles {
|
||||
currentMap := map[string]interface{}{}
|
||||
|
||||
bytes, err := readFile(filePath, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(bytes, ¤tMap); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse %s", filePath)
|
||||
}
|
||||
// Merge with the previous map
|
||||
base = mergeMaps(base, currentMap)
|
||||
}
|
||||
|
||||
// User specified a value via --set
|
||||
for _, value := range opts.Values {
|
||||
if err := strvals.ParseInto(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set data")
|
||||
}
|
||||
}
|
||||
|
||||
// User specified a value via --set-string
|
||||
for _, value := range opts.StringValues {
|
||||
if err := strvals.ParseIntoString(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set-string data")
|
||||
}
|
||||
}
|
||||
|
||||
// User specified a value via --set-file
|
||||
for _, value := range opts.FileValues {
|
||||
reader := func(rs []rune) (interface{}, error) {
|
||||
bytes, err := readFile(string(rs), p)
|
||||
return string(bytes), err
|
||||
}
|
||||
if err := strvals.ParseIntoFile(value, base, reader); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set-file data")
|
||||
}
|
||||
}
|
||||
|
||||
return base, nil
|
||||
}
|
||||
|
||||
func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{}, len(a))
|
||||
for k, v := range a {
|
||||
out[k] = v
|
||||
}
|
||||
for k, v := range b {
|
||||
if v, ok := v.(map[string]interface{}); ok {
|
||||
if bv, ok := out[k]; ok {
|
||||
if bv, ok := bv.(map[string]interface{}); ok {
|
||||
out[k] = mergeMaps(bv, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// readFile load a file from stdin, the local directory, or a remote file with a url.
|
||||
func readFile(filePath string, p getter.Providers) ([]byte, error) {
|
||||
if strings.TrimSpace(filePath) == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
u, _ := url.Parse(filePath)
|
||||
|
||||
// FIXME: maybe someone handle other protocols like ftp.
|
||||
g, err := p.ByScheme(u.Scheme)
|
||||
if err != nil {
|
||||
return ioutil.ReadFile(filePath)
|
||||
}
|
||||
data, err := g.Get(filePath, getter.WithURL(filePath))
|
||||
return data.Bytes(), err
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"getter.go",
|
||||
"httpgetter.go",
|
||||
"plugingetter.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/getter",
|
||||
importpath = "helm.sh/helm/v3/pkg/getter",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/internal/tlsutil:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/internal/urlutil:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/internal/version:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/cli:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/plugin:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"home.go",
|
||||
"lazypath.go",
|
||||
"lazypath_darwin.go",
|
||||
"lazypath_unix.go",
|
||||
"lazypath_windows.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/helmpath",
|
||||
importpath = "helm.sh/helm/v3/pkg/helmpath",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/helm.sh/helm/v3/pkg/helmpath/xdg:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:android": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:ios": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:nacl": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:plan9": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:solaris": [
|
||||
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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...))
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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")
|
||||
}
|
||||
|
|
@ -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") }
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["xdg.go"],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/helmpath/xdg",
|
||||
importpath = "helm.sh/helm/v3/pkg/helmpath/xdg",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
|
@ -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"
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"hooks.go",
|
||||
"plugin.go",
|
||||
],
|
||||
importmap = "k8s.io/kops/vendor/helm.sh/helm/v3/pkg/plugin",
|
||||
importpath = "helm.sh/helm/v3/pkg/plugin",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/helm.sh/helm/v3/pkg/cli:go_default_library",
|
||||
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
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"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"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"`
|
||||
|
||||
// UseTunnelDeprecated indicates that this command needs a tunnel.
|
||||
// Setting this will cause a number of side effects, such as the
|
||||
// automatic setting of HELM_HOST.
|
||||
// DEPRECATED and unused, but retained for backwards compatibility with Helm 2 plugins. Remove in Helm 4
|
||||
UseTunnelDeprecated bool `json:"useTunnel,omitempty"`
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// validPluginName is a regular expression that validates plugin names.
|
||||
//
|
||||
// Plugin names can only contain the ASCII characters a-z, A-Z, 0-9, _ and -.
|
||||
var validPluginName = regexp.MustCompile("^[A-Za-z0-9_-]+$")
|
||||
|
||||
// validatePluginData validates a plugin's YAML data.
|
||||
func validatePluginData(plug *Plugin, filepath string) error {
|
||||
if !validPluginName.MatchString(plug.Metadata.Name) {
|
||||
return fmt.Errorf("invalid plugin name at %q", filepath)
|
||||
}
|
||||
// We could also validate SemVer, executable, and other fields should we so choose.
|
||||
return nil
|
||||
}
|
||||
|
||||
func detectDuplicates(plugs []*Plugin) error {
|
||||
names := map[string]string{}
|
||||
|
||||
for _, plug := range plugs {
|
||||
if oldpath, ok := names[plug.Metadata.Name]; ok {
|
||||
return fmt.Errorf(
|
||||
"two plugins claim the name %q at %q and %q",
|
||||
plug.Metadata.Name,
|
||||
oldpath,
|
||||
plug.Dir,
|
||||
)
|
||||
}
|
||||
names[plug.Metadata.Name] = plug.Dir
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadDir loads a plugin from the given directory.
|
||||
func LoadDir(dirname string) (*Plugin, error) {
|
||||
pluginfile := filepath.Join(dirname, PluginFileName)
|
||||
data, err := ioutil.ReadFile(pluginfile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to read plugin at %q", pluginfile)
|
||||
}
|
||||
|
||||
plug := &Plugin{Dir: dirname}
|
||||
if err := yaml.UnmarshalStrict(data, &plug.Metadata); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to load plugin at %q", pluginfile)
|
||||
}
|
||||
return plug, validatePluginData(plug, pluginfile)
|
||||
}
|
||||
|
||||
// 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, errors.Wrapf(err, "failed to find plugins in %q", scanpath)
|
||||
}
|
||||
|
||||
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, detectDuplicates(plugins)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -816,6 +816,15 @@ gopkg.in/yaml.v2
|
|||
gopkg.in/yaml.v3
|
||||
# helm.sh/helm/v3 v3.4.2
|
||||
## explicit
|
||||
helm.sh/helm/v3/internal/tlsutil
|
||||
helm.sh/helm/v3/internal/urlutil
|
||||
helm.sh/helm/v3/internal/version
|
||||
helm.sh/helm/v3/pkg/cli
|
||||
helm.sh/helm/v3/pkg/cli/values
|
||||
helm.sh/helm/v3/pkg/getter
|
||||
helm.sh/helm/v3/pkg/helmpath
|
||||
helm.sh/helm/v3/pkg/helmpath/xdg
|
||||
helm.sh/helm/v3/pkg/plugin
|
||||
helm.sh/helm/v3/pkg/strvals
|
||||
# honnef.co/go/tools v0.0.1-2020.1.3
|
||||
honnef.co/go/tools/arg
|
||||
|
|
|
|||
Loading…
Reference in New Issue