Merge branch 'main' of github.com:helm/helm into hip-6

Signed-off-by: Josh Dolitsky <josh@dolit.ski>
pull/9782/head
Josh Dolitsky 4 years ago
commit 593eac8876
No known key found for this signature in database
GPG Key ID: B2B93673243A65FB

@ -1,5 +1,5 @@
run: run:
timeout: 2m timeout: 10m
linters: linters:
disable-all: true disable-all: true

@ -113,7 +113,7 @@ test-coverage:
.PHONY: test-style .PHONY: test-style
test-style: test-style:
GO111MODULE=on golangci-lint run --timeout 5m0s GO111MODULE=on golangci-lint run
@scripts/validate-license.sh @scripts/validate-license.sh
.PHONY: test-acceptance .PHONY: test-acceptance

@ -32,6 +32,7 @@ import (
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/gates" "helm.sh/helm/v3/pkg/gates"
"helm.sh/helm/v3/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake" kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/storage/driver" "helm.sh/helm/v3/pkg/storage/driver"
@ -59,6 +60,12 @@ func warning(format string, v ...interface{}) {
} }
func main() { func main() {
// Setting the name of the app for managedFields in the Kubernetes client.
// It is set here to the full name of "helm" so that renaming of helm to
// another name (e.g., helm2 or helm3) does not change the name of the
// manager as picked up by the automated name detection.
kube.ManagedFieldsManager = "helm"
actionConfig := new(action.Configuration) actionConfig := new(action.Configuration)
cmd, err := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) cmd, err := newRootCmd(actionConfig, os.Stdout, os.Args[1:])
if err != nil { if err != nil {

@ -58,6 +58,11 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
locked := make([]*chart.Dependency, len(reqs)) locked := make([]*chart.Dependency, len(reqs))
missing := []string{} missing := []string{}
for i, d := range reqs { for i, d := range reqs {
constraint, err := semver.NewConstraint(d.Version)
if err != nil {
return nil, errors.Wrapf(err, "dependency %q has an invalid version/constraint format", d.Name)
}
if d.Repository == "" { if d.Repository == "" {
// Local chart subfolder // Local chart subfolder
if _, err := GetLocalPath(filepath.Join("charts", d.Name), r.chartpath); err != nil { if _, err := GetLocalPath(filepath.Join("charts", d.Name), r.chartpath); err != nil {
@ -78,13 +83,22 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
return nil, err return nil, err
} }
// The version of the chart locked will be the version of the chart
// currently listed in the file system within the chart.
ch, err := loader.LoadDir(chartpath) ch, err := loader.LoadDir(chartpath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
v, err := semver.NewVersion(ch.Metadata.Version)
if err != nil {
// Not a legit entry.
continue
}
if !constraint.Check(v) {
missing = append(missing, d.Name)
continue
}
locked[i] = &chart.Dependency{ locked[i] = &chart.Dependency{
Name: d.Name, Name: d.Name,
Repository: d.Repository, Repository: d.Repository,
@ -93,11 +107,6 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
continue continue
} }
constraint, err := semver.NewConstraint(d.Version)
if err != nil {
return nil, errors.Wrapf(err, "dependency %q has an invalid version/constraint format", d.Name)
}
repoName := repoNames[d.Name] repoName := repoNames[d.Name]
// if the repository was not defined, but the dependency defines a repository url, bypass the cache // if the repository was not defined, but the dependency defines a repository url, bypass the cache
if repoName == "" && d.Repository != "" { if repoName == "" && d.Repository != "" {

@ -28,6 +28,18 @@ func TestResolve(t *testing.T) {
expect *chart.Lock expect *chart.Lock
err bool err bool
}{ }{
{
name: "repo from invalid version",
req: []*chart.Dependency{
{Name: "base", Repository: "file://base", Version: "1.1.0"},
},
expect: &chart.Lock{
Dependencies: []*chart.Dependency{
{Name: "base", Repository: "file://base", Version: "0.1.0"},
},
},
err: true,
},
{ {
name: "version failure", name: "version failure",
req: []*chart.Dependency{ req: []*chart.Dependency{

@ -21,6 +21,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"os"
"path/filepath"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -55,6 +57,10 @@ var ErrNoObjectsVisited = errors.New("no objects visited")
var metadataAccessor = meta.NewAccessor() var metadataAccessor = meta.NewAccessor()
// ManagedFieldsManager is the name of the manager of Kubernetes managedFields
// first introduced in Kubernetes 1.18
var ManagedFieldsManager string
// Client represents a client capable of communicating with the Kubernetes API. // Client represents a client capable of communicating with the Kubernetes API.
type Client struct { type Client struct {
Factory Factory Factory Factory
@ -100,7 +106,7 @@ func (c *Client) getKubeClient() (*kubernetes.Clientset, error) {
return c.kubeClient, err return c.kubeClient, err
} }
// IsReachable tests connectivity to the cluster // IsReachable tests connectivity to the cluster.
func (c *Client) IsReachable() error { func (c *Client) IsReachable() error {
client, err := c.getKubeClient() client, err := c.getKubeClient()
if err == genericclioptions.ErrEmptyConfig { if err == genericclioptions.ErrEmptyConfig {
@ -126,7 +132,7 @@ func (c *Client) Create(resources ResourceList) (*Result, error) {
return &Result{Created: resources}, nil return &Result{Created: resources}, nil
} }
// Wait up to the given timeout for the specified resources to be ready // Wait waits up to the given timeout for the specified resources to be ready.
func (c *Client) Wait(resources ResourceList, timeout time.Duration) error { func (c *Client) Wait(resources ResourceList, timeout time.Duration) error {
cs, err := c.getKubeClient() cs, err := c.getKubeClient()
if err != nil { if err != nil {
@ -206,7 +212,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err
return err return err
} }
helper := resource.NewHelper(info.Client, info.Mapping) helper := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager())
if _, err := helper.Get(info.Namespace, info.Name); err != nil { if _, err := helper.Get(info.Namespace, info.Name); err != nil {
if !apierrors.IsNotFound(err) { if !apierrors.IsNotFound(err) {
return errors.Wrap(err, "could not get information about the resource") return errors.Wrap(err, "could not get information about the resource")
@ -324,7 +330,7 @@ func (c *Client) watchTimeout(t time.Duration) func(*resource.Info) error {
// WatchUntilReady watches the resources given and waits until it is ready. // WatchUntilReady watches the resources given and waits until it is ready.
// //
// This function is mainly for hook implementations. It watches for a resource to // This method is mainly for hook implementations. It watches for a resource to
// hit a particular milestone. The milestone depends on the Kind. // hit a particular milestone. The milestone depends on the Kind.
// //
// For most kinds, it checks to see if the resource is marked as Added or Modified // For most kinds, it checks to see if the resource is marked as Added or Modified
@ -359,6 +365,26 @@ func perform(infos ResourceList, fn func(*resource.Info) error) error {
return nil return nil
} }
// getManagedFieldsManager returns the manager string. If one was set it will be returned.
// Otherwise, one is calculated based on the name of the binary.
func getManagedFieldsManager() string {
// When a manager is explicitly set use it
if ManagedFieldsManager != "" {
return ManagedFieldsManager
}
// When no manager is set and no calling application can be found it is unknown
if len(os.Args[0]) == 0 {
return "unknown"
}
// When there is an application that can be determined and no set manager
// use the base name. This is one of the ways Kubernetes libs handle figuring
// names out.
return filepath.Base(os.Args[0])
}
func batchPerform(infos ResourceList, fn func(*resource.Info) error, errs chan<- error) { func batchPerform(infos ResourceList, fn func(*resource.Info) error, errs chan<- error) {
var kind string var kind string
var wg sync.WaitGroup var wg sync.WaitGroup
@ -377,7 +403,7 @@ func batchPerform(infos ResourceList, fn func(*resource.Info) error, errs chan<-
} }
func createResource(info *resource.Info) error { func createResource(info *resource.Info) error {
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object) obj, err := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager()).Create(info.Namespace, true, info.Object)
if err != nil { if err != nil {
return err return err
} }
@ -387,7 +413,7 @@ func createResource(info *resource.Info) error {
func deleteResource(info *resource.Info) error { func deleteResource(info *resource.Info) error {
policy := metav1.DeletePropagationBackground policy := metav1.DeletePropagationBackground
opts := &metav1.DeleteOptions{PropagationPolicy: &policy} opts := &metav1.DeleteOptions{PropagationPolicy: &policy}
_, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, opts) _, err := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager()).DeleteWithOptions(info.Namespace, info.Name, opts)
return err return err
} }
@ -402,7 +428,7 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
} }
// Fetch the current object for the three way merge // Fetch the current object for the three way merge
helper := resource.NewHelper(target.Client, target.Mapping) helper := resource.NewHelper(target.Client, target.Mapping).WithFieldManager(getManagedFieldsManager())
currentObj, err := helper.Get(target.Namespace, target.Name) currentObj, err := helper.Get(target.Namespace, target.Name)
if err != nil && !apierrors.IsNotFound(err) { if err != nil && !apierrors.IsNotFound(err) {
return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name) return nil, types.StrategicMergePatchType, errors.Wrapf(err, "unable to get data for current object %s/%s", target.Namespace, target.Name)
@ -444,7 +470,7 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error { func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error {
var ( var (
obj runtime.Object obj runtime.Object
helper = resource.NewHelper(target.Client, target.Mapping) helper = resource.NewHelper(target.Client, target.Mapping).WithFieldManager(getManagedFieldsManager())
kind = target.Mapping.GroupVersionKind.Kind kind = target.Mapping.GroupVersionKind.Kind
) )

@ -30,14 +30,19 @@ type Interface interface {
// Create creates one or more resources. // Create creates one or more resources.
Create(resources ResourceList) (*Result, error) Create(resources ResourceList) (*Result, error)
// Wait waits up to the given timeout for the specified resources to be ready.
Wait(resources ResourceList, timeout time.Duration) error Wait(resources ResourceList, timeout time.Duration) error
// WaitWithJobs wait up to the given timeout for the specified resources to be ready, including jobs.
WaitWithJobs(resources ResourceList, timeout time.Duration) error WaitWithJobs(resources ResourceList, timeout time.Duration) error
// Delete destroys one or more resources. // Delete destroys one or more resources.
Delete(resources ResourceList) (*Result, []error) Delete(resources ResourceList) (*Result, []error)
// Watch the resource in reader until it is "ready". This method // WatchUntilReady watches the resources given and waits until it is ready.
//
// This method is mainly for hook implementations. It watches for a resource to
// hit a particular milestone. The milestone depends on the Kind.
// //
// For Jobs, "ready" means the Job ran to completion (exited without error). // For Jobs, "ready" means the Job ran to completion (exited without error).
// For Pods, "ready" means the Pod phase is marked "succeeded". // For Pods, "ready" means the Pod phase is marked "succeeded".
@ -49,9 +54,9 @@ type Interface interface {
// if it doesn't exist. // if it doesn't exist.
Update(original, target ResourceList, force bool) (*Result, error) Update(original, target ResourceList, force bool) (*Result, error)
// Build creates a resource list from a Reader // Build creates a resource list from a Reader.
// //
// reader must contain a YAML stream (one or more YAML documents separated // Reader must contain a YAML stream (one or more YAML documents separated
// by "\n---\n") // by "\n---\n")
// //
// Validates against OpenAPI schema if validate is true. // Validates against OpenAPI schema if validate is true.
@ -61,7 +66,7 @@ type Interface interface {
// and returns said phase (PodSucceeded or PodFailed qualify). // and returns said phase (PodSucceeded or PodFailed qualify).
WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error) WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error)
// isReachable checks whether the client is able to connect to the cluster // IsReachable checks whether the client is able to connect to the cluster.
IsReachable() error IsReachable() error
} }

Loading…
Cancel
Save